Bash: Strip trailing linebreak from output
Asked Answered
N

9

334

When I execute commands in Bash (or to be specific, wc -l < log.txt), the output contains a linebreak after it. How do I get rid of it?

Namnama answered 21/9, 2012 at 4:34 Comment(1)
Similar question hereDissolute
M
449

If your expected output is a single line, you can simply remove all newline characters from the output. It would not be uncommon to pipe to the tr utility, or to Perl if preferred:

wc -l < log.txt | tr -d '\n'

wc -l < log.txt | perl -pe 'chomp'

You can also use command substitution to remove the trailing newline:

echo -n "$(wc -l < log.txt)"

printf "%s" "$(wc -l < log.txt)"

If your expected output may contain multiple lines, you have another decision to make:

If you want to remove MULTIPLE newline characters from the end of the file, again use cmd substitution:

printf "%s" "$(< log.txt)"

If you want to strictly remove THE LAST newline character from a file, use Perl:

perl -pe 'chomp if eof' log.txt

Note that if you are certain you have a trailing newline character you want to remove, you can use head from GNU coreutils to select everything except the last byte. This should be quite quick:

head -c -1 log.txt

Also, for completeness, you can quickly check where your newline (or other special) characters are in your file using cat and the 'show-all' flag -A. The dollar sign character will indicate the end of each line:

cat -A log.txt
Maice answered 21/9, 2012 at 4:39 Comment(9)
This strips ALL newlines from the output, not just the trailing newline as the title asks.Decreasing
@CodyA.Ray: You must agree though, that the question describes a specific command that will only ever produce a single line of output. I have, however, updated my answer to suit the more general case. HTH.Maice
This would be better if the short options were replaced with long options. The long options teach as well as function e.g. tr --delete '\n'.Ento
I also did | tr -d '\r'Clavate
It's worth noting that the cmd substitution solution might lead to an overlong line if the file is very big.Chrysa
My up-vote is for the head -c ... version -- Because I can now feed commands to the clipboard and preserve formatting, but for the last \n. Eg.: alias clip="head -c -1 | xclip -selection clipboard", not too shabby. Now when you pipe ls -l | clip ... All that wonderful output goes to the X-Server clipboard without a terminating \n. Ergo ... I can paste that into my next command, just so. Many thanks!Signpost
Any reason for using head -c -1 instead of head -n -1, given that we know that it's a newline?Postrider
@Postrider head -n -1 removes the last line including its text and still leaves the previous EOL char in the output, so it doesn't do the same thing as head -c -1Deva
head -c -1 was what I needed since it is in the middle of a pipeline, perfect thanksDeva
C
96

One way:

wc -l < log.txt | xargs echo -n
Colt answered 21/9, 2012 at 4:36 Comment(5)
Better: echo -n `wc -l log.txt`Colt
Why is doing command execution in backticks better than using a pipe?Jon
These will not only remove the trailing newlines, but also squeeze any consecutive whitespaces (more precisely, as defined by IFS) to one space. Example: echo "a b" | xargs echo -n; echo -n $(echo "a b"). This may or may not be a problem for the use case.Watthour
Worse, if the output begins with -e, it will be interpreted as the option to echo. It's always safer to use printf '%s'.Watthour
xargs is very slow on my system (and I suspect it is on other systems too), so printf '%s' $(wc -l log.txt) might be faster, since printf is usually a builtin (Also because there is no information redirection). Never use backticks, they have been deprecated in newer POSIX versions and have numerous drawbacks.Naphthalene
S
28

If you want to remove only the last newline, pipe through:

sed -z '$ s/\n$//'

sed won't add a \0 to then end of the stream if the delimiter is set to NUL via -z, whereas to create a POSIX text file (defined to end in a \n), it will always output a final \n without -z.

Eg:

$ { echo foo; echo bar; } | sed -z '$ s/\n$//'; echo tender
foo
bartender

And to prove no NUL added:

$ { echo foo; echo bar; } | sed -z '$ s/\n$//' | xxd
00000000: 666f 6f0a 6261 72                        foo.bar

To remove multiple trailing newlines, pipe through:

sed -Ez '$ s/\n+$//'
Spermicide answered 27/9, 2019 at 6:45 Comment(4)
I suppose this is a GNU extension, Mac sed doesn't provide -z.Gredel
You can install gnu version of sed on mac, as gsed and use it, by doing what it says hereDissolute
Can someone explain what the $ in the beginning of the sed expression does?Chao
If I interpret it correctly, the $ is for selecting the last line and thus to avoid executing the sed command on all lines. See gnu.org/software/sed/manual/sed.html#Numeric-AddressesTransducer
A
24

There is also direct support for white space removal in Bash variable substitution:

testvar=$(wc -l < log.txt)
trailing_space_removed=${testvar%%[[:space:]]}
leading_space_removed=${testvar##[[:space:]]}
Adenocarcinoma answered 8/11, 2013 at 11:27 Comment(2)
You can also use trailing_linebreak_removed=${testvar%?}Swear
Note that if you are using command substitution then you don't need to do anything to remove trailing newlines. Bash already does that as part of command substitution: gnu.org/software/bash/manual/html_node/…Sweet
C
14

If you want to print output of anything in Bash without end of line, you echo it with the -n switch.

If you have it in a variable already, then echo it with the trailing newline cropped:

$ testvar=$(wc -l < log.txt)
$ echo -n $testvar

Or you can do it in one line, instead:

$ echo -n $(wc -l < log.txt)
Consensual answered 21/9, 2012 at 7:25 Comment(1)
The variable is technically unnecessary. echo -n $(wc -l < log.txt) has the same effect.Busiek
B
11

printf already crops the trailing newline for you:

$ printf '%s' $(wc -l < log.txt)

Detail:

  • printf will print your content in place of the %s string place holder.
  • If you do not tell it to print a newline (%s\n), it won't.
Brightwork answered 21/9, 2012 at 22:32 Comment(4)
If you put double quotes around the command like "$(command)", the internal newlines will be preserved -- and only the trailing newline will be removed. The shell is doing all the work here -- printf is just a way to direct the results of command substitution back to stdout.Aglow
It's not printf that's stripping the new line here, it's the shell that's doing it with the $( ) construct. Here's proof: printf "%s" "$(perl -e 'print "\n"')"Goodfornothing
Again, it's worth noting that the resulting command line might become too long.Chrysa
This is a convenient solution with @nobar's suggestion: $ printf '%s' "$(wc -l < log.txt)"Gemagemara
U
10

If you assign its output to a variable, bash automatically strips whitespace:

linecount=`wc -l < log.txt`
Urbanism answered 21/9, 2012 at 4:40 Comment(3)
Trailing newlines are stripped, to be exact. It's the command substitution that removes them, not the variable assignment.Busiek
I've seen in Cygwin bash the trailing whitespace not removed when using $(cmd /c echo %VAR%). In this case I've had to use ${var%%[[:space:]]}.Adenocarcinoma
Note: it is not the variable assignment, but the expression expansion that removes newlines.Monsour
S
9

Adding this for my reference more than anything else ^_^

You can also strip a new line from the output using the bash expansion magic

VAR=$'helloworld\n'

CLEANED="${VAR%$'\n'}"

echo "${CLEANED}"
Spirituous answered 26/7, 2021 at 8:24 Comment(0)
P
2

Using Awk:

awk -v ORS="" '1' log.txt 

Explanation:

  1. -v assignment for ORS
  2. ORS - output record separator set to blank. This will replace new line (Input record separator) with ""
Patchwork answered 19/5, 2021 at 3:25 Comment(1)
-1 (though I did not actually press the button for it since I would only be allowed to change it once). This removes all newlines, not just any leading or trailing ones.Fucus

© 2022 - 2024 — McMap. All rights reserved.