226

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.

kenorb
  • 137,499
  • 74
  • 643
  • 694
T. Webster
  • 9,065
  • 6
  • 64
  • 92
  • 2
    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.) – ruakh Mar 22 '13 at 21:50
  • similar to "http://stackoverflow.com/questions/2764051/how-to-join-multiple-lines-of-file-names-into-one-with-custom-delimiter" – Shervin Emami Apr 28 '17 at 07:25
  • Question with 68 votes (140k views) duplicated with post which has only 1 vote (12k views)? This isn't right. – kenorb Oct 29 '18 at 14:59
  • 1
    See: [Should I flag a question as duplicate if it has received better answers?](https://meta.stackoverflow.com/q/251938/55075) – kenorb Oct 29 '18 at 15:00

11 Answers11

335

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" 
Chris Seymour
  • 79,902
  • 29
  • 153
  • 193
  • 9
    You endup with an undesired space at the end with this approach. – sorin Mar 21 '16 at 12:27
  • 2
    You need to add `echo ""` at the end to add new line before prompt text. – nexayq Sep 09 '16 at 13:01
  • 1
    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? – oink Jan 19 '17 at 23:21
  • 3
    @oink you could pipe the results into `sed '$s/..$//'` to delete the last 2 characters on the last line. – Chris Seymour Jan 19 '17 at 23:27
  • 7
    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'`. – Elijah Lynn Dec 20 '18 at 05:42
102

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.

bluebadge
  • 1,129
  • 1
  • 8
  • 5
  • `| 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. – Adarsha Mar 26 '15 at 17:07
  • 5
    This solution also has the advantage that it 'eats' spaces from the input. +1 – Rene Aug 11 '15 at 10:23
  • This would remove all double quotes `"`. Not suitable for JSON. – dz902 May 10 '22 at 16:44
94

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

echo $(cat file)
simhumileco
  • 27,137
  • 16
  • 123
  • 105
user1699917
  • 1,229
  • 9
  • 5
  • 15
    Severely underrated answer here, this is really simple and works like a charm, with a trailing newline as well. – Dangercrow Jan 03 '17 at 11:55
  • This is especially neat if you use `IFS="$(printf '\n\t')"` – aggsol Jan 20 '17 at 11:13
  • 6
    Or just `echo $( – Normadize Apr 13 '17 at 16:34
  • How about without space? – DimiDak Nov 28 '19 at 10:18
  • 1
    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. – Chris Sep 01 '21 at 20:39
  • 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' )` – psmith Apr 21 '22 at 03:55
24

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)

sehe
  • 350,152
  • 45
  • 431
  • 590
  • 2
    @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) – sehe Oct 05 '15 at 06:46
12

This is an example which produces output separate 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
Richard Gomes
  • 5,245
  • 1
  • 42
  • 46
7

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).

simhumileco
  • 27,137
  • 16
  • 123
  • 105
5

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
ascendants
  • 1,555
  • 2
  • 8
  • 21
5

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
JoL
  • 927
  • 9
  • 15
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!

kenorb
  • 137,499
  • 74
  • 643
  • 694
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

-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.

  • 5
    This as already been answer in 2015. You are just duplicating [this answer](https://stackoverflow.com/a/33540439/9434800). Please read answers before posting your own, specially when the question is 7 years old and there are already 8 answers. – Mickael B. May 08 '20 at 14:18