296

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.

4
  • 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.) Commented Mar 22, 2013 at 21:50
  • similar to "stackoverflow.com/questions/2764051/…" Commented Apr 28, 2017 at 7:25
  • 1
    Question with 68 votes (140k views) duplicated with post which has only 1 vote (12k views)? This isn't right. Commented Oct 29, 2018 at 14:59
  • 1
    See: Should I flag a question as duplicate if it has received better answers? Commented Oct 29, 2018 at 15:00

12 Answers 12

408

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" 
Sign up to request clarification or add additional context in comments.

6 Comments

You endup with an undesired space at the end with this approach.
You need to add echo "" at the end to add new line before prompt text.
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 you could pipe the results into sed '$s/..$//' to delete the last 2 characters on the last line.
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'.
|
129

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

echo $(cat file)

7 Comments

Severely underrated answer here, this is really simple and works like a charm, with a trailing newline as well.
This is especially neat if you use IFS="$(printf '\n\t')"
Or just echo $(<file) ... using echo is not just neater than using tr '\n' ' ', but also better (think \r\n line endings). @aggsol you can just say IFS=$'\n\t'
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.
@aggsol IFS=$'\n\t' should do the same thing w/o a subshell.
|
126

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.

3 Comments

| 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.
This solution also has the advantage that it 'eats' spaces from the input. +1
This would remove all double quotes ". Not suitable for JSON.
28

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)

1 Comment

@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)
20

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

Comments

9

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

Comments

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

Comments

8

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

Comments

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!

Comments

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

Comments

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 Comment

You don't need {print} since its the default action of awk.
-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.

1 Comment

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.