sed
won't work (easily) because it operates on lines one at a time; you could do it, but it would involve copying the whole input into the hold buffer
tr
actually should work the way you pasted it; are you sure the newlines are \n
s? You can simplify it a bit by deleting the newlines instead of converting them to spaces:
tr -d '\n'
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
If all you want to do is add text to the last line, it's very easy with sed. Replace
$
(pattern matching at the end of the line) by the text you want to add, only on lines in the range$
(which means the last line).which on Linux can be shortened to
If you want to remove the last byte in a file, Linux (more precisely GNU coreutils) offers the
truncate
command, which makes this very easy.A POSIX way to do it is with
dd
. First determine the file length, then truncate it to one byte less.Note that both of these unconditionally truncate the last byte of the file. You may want to check that it's a newline first: