Here's one way using GNU sed
:
sed -n '/--/,/Content-Length: 0/ { H; /Content-Length: 0/ { g; s/\n\(.*\)\n.*--.*/\1/p } }'
Result:
line 1 "--"
line 2
line 3 "Content-Length: 20"
Explanation:
Match between the pattern range. Append this range to the hold space. On the last
line of the range, copy the hold space to pattern space to work with it. Then use
find/replace regex to remove everything after the last occurrence of '--'. HTH.
Answer
perl -0777 -p -i -e 's/,(\n*)\Z/\1/m' *.txt
will remove the last ',' in all files ending in .txt
, if the ',' is followed only by 0-or-more newline characters then the end of the file.
From your example:
reedm@www:~/tmp $ cat > test.txt
blah blah blah,
blah blah blah,
blah blah blah,
reedm@www:~/tmp $ perl -0777 -p -i -e 's/,(\n*)\Z/\1/m' *.txt
reedm@www:~/tmp $ cat test.txt
blah blah blah,
blah blah blah,
blah blah blah
reedm@www:~/tmp $
Wat?
Perl is an esoteric beast at the best of times, and perl one-liners can be particularly cryptic.
The -e
flag allows us to pass a perl program on the command line. In this case, the 's/regex/replace/flags' is the program.
The -p
flag causes perl to apply your supplied program in a loop over each "line" (see -0
) for each filename provided.
The -i
flag causes perl to replace the file with the output of the program, rather than printing the output to standard out.
The -0
flag changes what delimiter perl uses to break a file into "lines". 0777
is a special value, used by convention to make perl read the entire file into a single "line".
The regular expression is somewhat complicated by the use of a few perl-specific tricks:
- First, the
m
flag at the end causes the regex to operate on
multiple lines.
,
is simple, and matches a single, literal comma.
(\n*)
matches 0-or-more newlines in a row, and stores them as a
subpattern (the (
and )
characters denote a subpattern). As this
is the first subpattern, we can use \1
in the replacement section
to mean "whatever this subpattern matched".
\Z
is a perl specific extension, and matches the end of the string
being worked with -- in this case, that's the entire file.
- In the replacement part, we use
\1
to replace the match with only
the series of newlines, removing the comma.
For man information on perl regular expressions and perl command line flags, check out the man pages for perlre
and perlrun
respectively.
Best Answer
To replace commas with semicolons on the last n lines with
ed
:Splitting that apart:
ed -s
= run ed silently (don't report the bytes written at the end)'$-'
= from the end of the file ($
) minus ...$((n-1))
= n-1 lines ...$' ... '
= quote the rest of the command to protect it from the shell ),$s/,/;/g
= ... until the end of the file (,$
), search and replace all commas with semicolons.\nwq
= end the previous command, then save and quitTo replace commas with semicolons on the last n lines with
sed
:Breaking that apart:
-i
= edit the file "in-place"$(( ... ))
= do some math:$( wc -l < input)
= get the number of lines in the file-n + 1
= go backwards n-1 lines,\$
= from n-1 lines until the end of the file:s/,/;/g
= replace the commas with semicolons.