1

I am trying to concatenate the results of my grep search. my grep search finds about 4 files on my system and outputs them in a new line for each file. I thought by passing this information to tr '\n' ' ' I would get all of the files from the search on one line and then pass it to cat > bigfile to have big file contain all of the files content from my search. Instead bigfile just contains the list of files that grep found.

How do I make bigfile contain a concatenation of all of the files that grep found.

Here is the code I have tried:

egrep -Rl 'users.*log|log.*users' /home/moose/test | tr '\n' ' ' | cat > bigfile

and then bigfile contains:

/home/moose/test/file1 /home/moose/test/2 /home/moose/test/3 /home/moose/moose/file4 

Thank You

4

If you are trying to concatenate the contents of the matching files into a single bigfile, then you need to pass the filenames to cat as distinct arguments: you could do that with xargs

egrep -ZRl 'users.*log|log.*users' /home/moose/test | xargs -0 cat

The addition of the -Z and -0 flags passes the names using null delimiters, allowing the command to work with any legal filenames (including those containing whitespace or newlines).

1
  1. cat does nothing here. Simply redirecting the output of tr is effectively the same as piping it to cat and redirecting.

  2. Try paste instead of tr. For example:

    egrep -Rl 'users.*log|log.*users' /home/moose/test | paste -sd' ' > bigfile

  3. xargs works too, and has the advantage of splitting the output into multiple lines if/when it reaches the maximum length of a command-line:

    egrep -Rl 'users.*log|log.*users' /home/moose/test | xargs > bigfile

BTW, why does it even matter if the files are listed one per line or all on one line? If you intend to use it in the command line of another program or as input to a for or while loop, you're probably better off with one filename per line anyway, especially if there's any files with space characters in the filename.

  • The way I read it, the questioner is trying to concatenate the contents of the matching files - something like egrep -ZRl 'users.*log|log.*users' /home/moose/test | xargs -0 cat perhaps? – steeldriver Mar 9 '16 at 1:40
  • the example output shows a list of filenames, all on one line....but, yeah, if your interpretation is correct, xargs cat will do the job, and null-terminated filenames are perfect. You should post it as an answer. – cas Mar 9 '16 at 1:57
0

No need for the last pipe / cat, you can redirect it to the file directly after tr

Can use your code like:

egrep -Rl 'users.*log|log.*users' /home/moose/test | tr '\n' ' ' > bigfile

This will give you:

/home/moose/test/file1 /home/moose/test/2 /home/moose/test/3 /home/moose/moose/file4

  • 1
    The problem with using tr rather than paste or xargs is that it also replaces the \n that terminates the line...and many tools that process text don't work properly if the final input line doesn't have a \n (they typically ignore that line). – cas Mar 9 '16 at 1:32
0

You can use paste with -s (serialize) option to get all the lines in a single one.

In your case:

grep .... | paste -sd'\t'

Here, -t indicates delimiter, using tab here as the delimiter, change it to fit your need.

Example:

% printf 'foo\nbar\nspam\negg\n'               
foo
bar
spam
egg

% printf 'foo\nbar\nspam\negg\n' | paste -sd' ' 
foo bar spam egg

% printf 'foo\nbar\nspam\negg\n' | paste -sd'\t'
foo   bar   spam    egg

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.