How to concatenate multiple lines of output to one line?
Asked Answered
M

12

268

If I run the command cat file | grep pattern, I get many lines of output. How do you concatenate all lines into one line, effectively replacing each "\n" with "\" " (end with " followed by space)?

cat file | grep pattern | xargs sed s/\n/ /g isn't working for me.

Matzo answered 22/3, 2013 at 21:27 Comment(4)
By the way: (1) you need to put your sed script in single-quotes so that Bash doesn't mess with it (since sed s/\n/ /g calls sed with two arguments, namely s/n/ and /g); (2) since you want the output of cat file | grep pattern to be the input to sed, not the arguments to sed, you need to eliminate xargs; and (3) there's no need for cat here, since grep can take a filename as its second argument. So, you should have tried grep pattern file | sed 's/\n/ /g'. (In this case it wouldn't have worked, for reasons given at the above link, but now you know for the future.)Manche
similar to "#2764551"Tapia
Question with 68 votes (140k views) duplicated with post which has only 1 vote (12k views)? This isn't right.Middlebuster
See: Should I flag a question as duplicate if it has received better answers?Middlebuster
R
382

Use tr '\n' ' ' to translate all newline characters to spaces:

$ grep pattern file | tr '\n' ' '

Note: grep reads files, cat concatenates files. Don't cat file | grep!

Edit:

tr can only handle single character translations. You could use awk to change the output record separator like:

$ grep pattern file | awk '{print}' ORS='" '

This would transform:

one
two 
three

to:

one" two" three" 
Resonate answered 22/3, 2013 at 21:31 Comment(5)
You endup with an undesired space at the end with this approach.Barcroft
You need to add echo "" at the end to add new line before prompt text.Eviaevict
This works out nicely, however I don't want the separator to show up on the very last entry. Example, per your ", it shows up like one" two" three", however I'd want it to show up like one" two" three. Note the last three doesn't have a parenthesis. Any ideas?Calyces
@Calyces you could pipe the results into sed '$s/..$//' to delete the last 2 characters on the last line.Resonate
If you want to replace newlines with nothing, you need to use the --delete option as the default expects two arguments. e.g. tr --delete '\n'.Larrisa
S
122

In bash echo without quotes remove carriage returns, tabs and multiple spaces

echo $(cat file)
Staphylococcus answered 5/11, 2015 at 9:11 Comment(6)
Severely underrated answer here, this is really simple and works like a charm, with a trailing newline as well.Prato
This is especially neat if you use IFS="$(printf '\n\t')"Cafard
Or just echo $(<file) ... using echo is not just neater than using tr '\n' ' ', but also better (think \r\n line endings). @Cafard you can just say IFS=$'\n\t'Romito
How about without space?Dropkick
Works very nicely on Unix systems - but Windows (eg. MSYS2 / Git Bash) doesn't behave the same way - could be other systems that don't work the same way as well. awk works most reliably for me cross-platform.Weighin
I wanted to use this to grep certain headers from the curl response, and apparently headers have a \r which messed up the output, so you need to delete the \r chars like this: echo $(curl ... 2>&1 | grep my-headers | tr -d '\r' )Manteltree
S
120

Piping output to xargs will concatenate each line of output to a single line with spaces:

grep pattern file | xargs

Or any command, eg. ls | xargs. The default limit of xargs output is ~4096 characters, but can be increased with eg. xargs -s 8192.

Sonya answered 11/8, 2014 at 20:35 Comment(3)
| tr '\n' ' ' was not working for me when called through php exec function. It was ignoring tr, and just giving last match from grep. | xargs worked.Glyconeogenesis
This solution also has the advantage that it 'eats' spaces from the input. +1Piperine
This would remove all double quotes ". Not suitable for JSON.Peppel
T
25

This could be what you want

cat file | grep pattern | paste -sd' '

As to your edit, I'm not sure what it means, perhaps this?

cat file | grep pattern | paste -sd'~' | sed -e 's/~/" "/g'

(this assumes that ~ does not occur in file)

Three answered 22/3, 2013 at 21:41 Comment(1)
@Stephan there was no need to assume that cat file will actually be cat, or even a file. (I just left that part unchanged as it was irrelevant to the question)Three
D
18

This is an example which produces output separated by commas. You can replace the comma by whatever separator you need.

cat <<EOD | xargs | sed 's/ /,/g'
> 1
> 2
> 3
> 4
> 5
> EOD

produces:

1,2,3,4,5
Dotted answered 2/8, 2018 at 12:26 Comment(0)
B
8

The fastest and easiest ways I know to solve this problem:

When we want to replace the new line character \n with the space:

xargs < file

xargs has own limits on the number of characters per line and the number of all characters combined, but we can increase them. Details can be found by running this command: xargs --show-limits and of course in the manual: man xargs

When we want to replace one character with another exactly one character:

tr '\n' ' ' < file

When we want to replace one character with many characters:

tr '\n' '~' < file | sed s/~/many_characters/g

First, we replace the newline characters \n for tildes ~ (or choose another unique character not present in the text), and then we replace the tilde characters with any other characters (many_characters) and we do it for each tilde (flag g).

Bonnibelle answered 6/2, 2020 at 18:55 Comment(0)
O
8

Here is another simple method using awk:

# cat > file.txt
a
b
c

# cat file.txt | awk '{ printf("%s ", $0) }'
a b c

Also, if your file has columns, this gives an easy way to concatenate only certain columns:

# cat > cols.txt
a b c
d e f

# cat cols.txt | awk '{ printf("%s ", $2) }'
b e
Olenta answered 23/7, 2020 at 15:15 Comment(0)
G
7

I like the xargs solution, but if it's important to not collapse spaces, then one might instead do:

sed ':b;N;$!bb;s/\n/ /g'

That will replace newlines for spaces, without substituting the last line terminator like tr '\n' ' ' would.

This also allows you to use other joining strings besides a space, like a comma, etc, something that xargs cannot do:

$ seq 1 5 | sed ':b;N;$!bb;s/\n/,/g'
1,2,3,4,5
Greatgrandaunt answered 3/8, 2020 at 13:23 Comment(0)
M
4

Here is the method using ex editor (part of Vim):

  • Join all lines and print to the standard output:

    $ ex +%j +%p -scq! file
    
  • Join all lines in-place (in the file):

    $ ex +%j -scwq file
    

    Note: This will concatenate all lines inside the file it-self!

Middlebuster answered 20/12, 2016 at 22:19 Comment(0)
A
1

paste -sd'~' giving error.

Here's what worked for me on mac using bash

cat file | grep pattern | paste -d' ' -s -

from man paste .

-d list     Use one or more of the provided characters to replace the newline characters instead of the default tab.  The characters
                 in list are used circularly, i.e., when list is exhausted the first character from list is reused.  This continues until
                 a line from the last input file (in default operation) or the last line in each file (using the -s option) is displayed,
                 at which time paste begins selecting characters from the beginning of list again.

                 The following special characters can also be used in list:

                 \n    newline character
                 \t    tab character
                 \\    backslash character
                 \0    Empty string (not a null character).

                 Any other character preceded by a backslash is equivalent to the character itself.

     -s          Concatenate all of the lines of each separate input file in command line order.  The newline character of every line
                 except the last line in each input file is replaced with the tab character, unless otherwise specified by the -d option.
                 If ‘-’ is specified for one or more of the input files, the standard input is used; standard input is read one line at a time,  

circularly, for each instance of ‘-’.

Architectonics answered 11/10, 2022 at 22:49 Comment(0)
D
0

Probably the best way to do it is using 'awk' tool which will generate output into one line

$ awk ' /pattern/ {print}' ORS=' ' /path/to/file

It will merge all lines into one with space delimiter

Drogin answered 12/3, 2018 at 11:22 Comment(1)
You don't need {print} since its the default action of awk.Georgiana
G
-1

On red hat linux I just use echo :

echo $(cat /some/file/name)

This gives me all records of a file on just one line.

Glyptics answered 8/5, 2020 at 12:30 Comment(1)
This as already been answer in 2015. You are just duplicating this answer. Please read answers before posting your own, specially when the question is 7 years old and there are already 8 answers.Parlormaid

© 2022 - 2024 — McMap. All rights reserved.