How can I delete a trailing newline in bash?

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"

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:

  1. NR>1{print PREV} Print previous line (except the first time).
  2. {PREV=$0} Stores current line in PREV variable.
  3. 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").


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.