How can I delete a trailing newline in bash?
Solution 1
This should work:
printf "one\ntwo\n" | awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}' ; echo " done"
The script always prints previous line instead of current, and the last line is treated differently.
What it does in more detail:
-
NR>1{print PREV}
Print previous line (except the first time). -
{PREV=$0}
Stores current line inPREV
variable. -
END{printf("%s",$0)}
Finally, print last line withtout line break.
Also note this would remove at most one empty line at the end (no support for removing "one\ntwo\n\n\n"
).
Solution 2
You can use perl
without chomp
:
$ printf "one\ntwo\n" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done
$ printf "one\ntwo" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done
But why not use chomp
itself:
$ printf "one\ntwo\n" | perl -pe 'chomp if eof'; echo " done"
Solution 3
If you want an exact equivalent to chomp
, the first method that comes to my mind is the awk solution that LatinSuD already posted. I'll add some other methods that don't implement chomp
but implement some common tasks that chomp
is often used for.
When you stuff some text into a variable, all newlines at the end are stripped. So all these commands produce the same single-line output:
echo "$(printf 'one\ntwo') done"
echo "$(printf 'one\ntwo\n') done"
echo "$(printf 'one\ntwo\n\n') done"
echo "$(printf 'one\ntwo\n\n\n\n\n\n\n\n\n\n') done"
If you want to append some text to the last line of a file or of a command's output, sed
can be convenient. With GNU sed and most other modern implementations, this works even if the input doesn't end in a newline¹; however, this won't add a newline if there wasn't one already.
sed '$ s/$/ done/'
¹ However this doesn't work with all sed implementations: sed is a text processing tool, and a file that isn't empty and doesn't end with a newline character is not a text file.
Solution 4
I found bash was able to do what I wanted without any other tools. This isn't going to replicate chomp
precisely but might help someone.
A command whose output ends with a newline will have it chomped during substitution:
the_output=$(my_command_with_a_newline)
It can be used as part of a pipeline with echo -n
(quote the substitution to preserve the other newlines):
echo -n "$(my_command_with_a_newline)" |tail_or_whatever
Using printf "one\ntwo\n"
like the OP:
$ echo -n "$(printf "one\ntwo\n")"; echo " done"
one
two done
Solution 5
Another perl
approach. This one reads the entire input into memory so it might not be a good idea for large amounts of data (use cuonglm's or the awk
approach for that):
$ printf "one\ntwo\n" | perl -0777pe 's/\n$//'; echo " done"
one
two done
Related videos on Youtube

Flimm
Updated on September 18, 2022Comments
-
Flimm 3 months
I'm looking for something that behaves like Perl's
chomp
. I'm looking for a command that simply prints its input, minus the last character if it's a newline:$ printf "one\ntwo\n" | COMMAND_IM_LOOKING_FOR ; echo " done" one two done $ printf "one\ntwo" | COMMAND_IM_LOOKING_FOR ; echo " done" one two done
(Command substitution in Bash and Zsh deletes all trailing new lines, but I'm looking for something that deletes one trailing new line at most.)
-
Flimm over 8 yearsThis is not exactly equivalent to
chomp
, aschomp
only deletes at most one trailing newline. -
Gilles 'SO- stop being evil' over 8 years@Flimm Yes, the most obvious exact equivalent to
chomp
would be the awk solution that LatinSuD already posted. But in many caseschomp
is just a tool to do a job, and I provide ways to do some common tasks. Let me update my answer to clarify this. -
terdon about 3 yearsThanks, @StéphaneChazelas, fixed. For some reason, this switch always confuses me!
-
Flimm over 2 yearsBash will remove all trailing newlines in command substitution, not just one, see for yourself:
foobar="$(echo -e 'hello\n\n\n'); printf %s "$foobar"