19

I use ubuntu 14.4, and been attempting to redirect the output of grep command to a file, but I keep getting this error:

grep: input file 'X' is also the output

I run the following command:

grep -E -r -o -n r"%}(.*){%" > myfile

As the error states, it seems that somehow it's interpreting the input and output as same name/obj. I searched but couldn't find what exactly is the problem?!

Mazdak
  • 933
  • If you are trying grep pattern file > file then it doesn't work. You cannot use the same file as input and output for grep. – jimmij Oct 25 '14 at 21:29
  • i add my command ! thanks for hint , but when i try to use a file in other path the does not predicate it and i cant do that ! – Mazdak Oct 25 '14 at 21:34
  • for example with ../f i get this bash: ../f.txt: Permission denied – Mazdak Oct 25 '14 at 21:37
  • show full command, what is your input file, or are you using the pipe? – jimmij Oct 25 '14 at 21:42
  • Yes, please show the entire command. It's unclear what you're asking us at this point, so unlikely that anyone will be able to help you further. – slm Oct 25 '14 at 21:43
  • @jimmij hey, thanks for your hint , i do it whit grep -E -r -o -n "%}(.*){%" >> /home/user_name/Desktop/a.txt – Mazdak Oct 25 '14 at 21:43
  • @jimmij please add your command as an answer ! i think its deserved to approved ! – Mazdak Oct 25 '14 at 21:44
  • 2
    Now I understand that you are actually greping recursively the whole directory structure and want to append the result to the file which already exists in this structure. The problem is that shell (bash, zsh, whatever) first performs redirections and only then goes back to commands (grep in this example). It means that grep in command grep pattern file > file sees already empty file, so has nothing as input. However if you use >> instead of > then the file is not empty, but grep throws error anyhow as it may lead to recursive processing the same line (pattern) over and over again. – jimmij Oct 25 '14 at 22:22

7 Answers7

15

It is not possible to use the same file as input and output for grep. You may consider the following alternatives:

  • temporary file

    grep pattern file > tmp_file
    mv tmp_file file
    
  • sed

    sed -i -n '/pattern/p' file
    
  • put whole file in the variable (not bright idea for large files)

    x=$(cat file); echo "$x" | grep pattern > file
    
jimmij
  • 47,140
  • 1
    sed can be more portable sed -i '/pattern/!d' file – Costas Oct 25 '14 at 21:53
  • But in the case OP wants sed -i -n 's/.*\(pattern\).*/\1/p' file – Costas Oct 25 '14 at 22:20
  • @Costas you are right, the question was edited and additional info added so one can polish sed syntax as well. – jimmij Oct 25 '14 at 22:35
  • Why exactly it is not possible to use the same file as input and output for grep? – pmor Feb 15 '22 at 17:15
  • @pmor Because shell first takes care of redirections and only then executes the commands, so the file will be truncated by the time grep connects it as an input. – jimmij Feb 15 '22 at 21:38
7

You can use the --exclude field in your grep command like so:

grep  --exclude=myfile  -Eron  r"%}(.*){%"  >  myfile
  • 5
    Make sure myfile is unique as it only applies to the file's basename. You don't want to skip files with the same name in other directories. – Walf Mar 07 '17 at 00:45
  • This answer better fits the original question, which involved file tree recursion. – anthony Oct 07 '22 at 05:15
3

Simply do this

echo "$(grep pattern file)" > file
2

With GNU find and GNU grep (as found on Ubuntu), you could do:

find . -type f ! -samefile myfile \
  -exec grep -Hon 'r%}(.*){%' {} + > myfile

Or to also look in symlinks to regular files (like some greps do with -r):

find -L . '(' ! -xtype l -o -prune ')' ! -samefile myfile -type f \
  -exec grep -Hon 'r%}(.*){%' {} + > myfile

! -samefile myfile will make sure myfile or any hardlink (or symlink in the one with -L) to it is not included in the list of files grep will look in.

Another option is to use moreutils's sponge:

grep -Hon 'r%}(.*){%' . | sponge myfile

sponge will delay writing to the file until eof on its stdin, so until grep has finished (note however that to do that, it stores the whole input in memory).

1

I found a way in bash: cat >> IN_OUTPUT_FILE <<< "$(grep something IN_OUTPUT_FILE)"

The command in <<<"..." will be executed first.

osexp2000
  • 502
0

That's because grep will continue to look into that folder after the creation of myfile.

You can simply give it another path:

grep -E -r -o -n r"%}(.*){%" > /tmp/myfile
Greenonline
  • 1,851
  • 7
  • 17
  • 23
0

Just use tee instead of redirecting:

grep pattern file | tee file
mchid
  • 1,420