views:

60

answers:

3
+1  Q: 

N-Insert In Sed

How would I replace the first 150 characters of every line with spaces using sed. I don't want to bring out the big guns (Python, Perl, etc) and it seems like sed is pretty powerful in itself (some people have written the dc calculator in it for example). A related problem is inserting 150 spaces in front of every line.

s/^.\{50\}/?????/

That matches the first 50 characters but then what? I can't do output

s/^.\{50\}/ \{50\}/

One could use readline to simulate 150 presses (alt+150, ) but that's lame.

+2  A: 

Basically you want to do this:

sed -r "s/^.{150}/$(giveme150spaces)/"

The question is just what's the most elegant way to programatically get 150 spaces. A variety of techniques are discussed here: Bash Hacker's Wiki. The simplest is to to use printf '%150s', like this:

sed -r "s/^.{150}/$(printf '%150s')/"
profjim
Can the printf solution be applied to the OP's request for a solution using sed?
JP Lodine
edited to be more explicit
profjim
+1  A: 

Use the hold space.

/^.\{150\}/ {;# simply echo lines shorter than 150 chars
    h;# make a backup
    s/^.\{150\}\(.*\)/\1/;# strip 150 characters
    x;# swap backup in and remainder out
    s/^\(.\{150\}\).*/\1/;# only keep 150 characters
    s/./ /g;# replace every character with a space
    G;# append newline + remainder to spaces
    s/\n//;# strip pesky newline
};

Alternately, you could code a loop (somewhat shorter code):

s/^.\{150\}/x/;# strip 150 characters & mark beginning of line
t l
# if first substitution matched, then loop
d; # else abort and go to next input line
:l
# begin loop
s/^/ /;# insert a space
/^ \{150\}x/!t l
# if line doesn't begin with 150 spaces, loop
s/x//;# strip beginning marker

However, I don't think you can use a loop without sed -f, or finding some other way to escape newlines. Label names seem to run to the end of the line, right through a ;.

Potatoswatter
more work, but more satisfying. +1
profjim
Thaat is pro :)
Elite Mx
As above, with some corrections: `sed -n '/^.\{150\}/ {h; s/^.\{150\}\(.*\)/\1/; x; s/^\(.\{150\}\).*/\1/; s/./ /g; G; s/\n//; p}'` The original prints the two parts of the line on separate lines (in other words, adds an extra newline, is missing back slashes on the first set of braces and doesn't include the necessary "-n". +1 in any case, however.
Dennis Williamson
@Elite, @Dennis: sorry to make you guys work, apparently I posted my correction mere seconds after several people read the answer :vP — and it looks like my correction is identical to your code, Dennis, give or take behavior on short lines.
Potatoswatter
-1. things can be much simpler.
@levis: Such as? The other answers all use other tools.
Potatoswatter
@Pot. sed uses regex and little alphabet characters to represent a specific operations. Though the code may be concise and does what you want, too much of it, coupled with regex , makes the code not easy to read and understand.
@levis: So you downvoted me because it looked ugly when I solved a difficult problem? Regardless of whether a prettier solution even exists?
Potatoswatter
@pot, firstly, its not a difficult problem to solve, and i know it. secondly, your solution doesn't appeal to me (and i certainly would not want to maintain it) because simpler solutions exist that doesn't need to much explanation of what its doing. (like what protjim has). lastly, don't take it too hard on the downvote, since its SO we are talking about.
@levis: agreed, I view sed is an esoteric language and I can't really recommend it for this purpose, but it's what was specified in the question. I'd take well-commented sed over perl any day, though.
Potatoswatter
+1  A: 

The logic is to iterate the file, print 150 spaces, and then print the rest of the line from 151 till the end using "substringing". eg for first 10 chars.

$ more file
1234567890abc
0987654321def
$ awk '{printf "%10s%s\n", " ",substr($0,11)}' file
          abc
          def

this is much simpler than crafting regex.

Bash:

while read -r line
do
    printf "%10s%s\n" " " "${line:10}"
done <"file"
ghostdog74