简体   繁体   中英

Using find, grep and sed together

I am trying to find all occurrences of files which have a specified string in them and then clear out the contents of all those files. So a file with "stringtofind" within it would subsequently be an empty file.

To do this I have tried the following, but I get errors:

With the following I get error: find: missing argument to `-exec'

 find / -maxdepth 1 -xdev -type f -exec grep -i "stringtofind" -l -exec sed -i '/./d'

With the following I get error:

grep: /nis

/tset.any

/test2.file

/test.txt

: No such file or directory sed: no input files

find / -maxdepth 1 -xdev -type f -print | xargs -0 grep -i "stringtofind" -l | xargs sed -i '/./d'

your find command with the missing argument is very close to working. try:

find / -maxdepth 1 -xdev -type f -exec grep -i "stringtofind" -l {} \; -exec sed -i '/./d' {} \;

you just need to add a backslash escaped semi-colon to the end of each -exec action and add {} to let it know where to substitute the filename.

You need to specify a file marker ( {} ) and termination (either ; or + ) to -exec . In addition I would suggest that you process the files with GNU parallel:

find / -maxdepth 1 -xdev -type f -exec grep -li "stringtofind" {} + | 
  parallel sed "'/./d'" '{}'

To handle filenames with newlines in them you need to use zero termination as suggested by others:

find / -maxdepth 1 -xdev -type f -exec grep -Zli "stringtofind" {} + | 
  parallel -0 sed "'/./d'" '{}'

Edit

Here's a non-parallel dependent alternative:

find / -maxdepth 1 -xdev -type f -exec grep -Zli "stringtofind" {} + | 
  while IFS= read -r -d $'\0' file; do
    sed '/./d' "$file"
  done

You have an issue with file names containing spaces. When using the -0 argument to xargs , you should use -print0 as final argument to find . grep should be happy with this.

However, while this will solve the issue in the pipe between find and grep , it will not allow to pass the zero-separated name in the pipe from grep to sed . Therefore, sed will still complain ...

Therefore, you should test with grep within find using -exec , and use a single pipe to sed , as follows. Note the use of double quotes " around the {} placeholder.

find / -maxdepth 1 -xdev -type f -exec grep -i "stringtofind" -q "{}" \; -print0 | xargs -0 sed '/./d'

It gives you the advantage to be able to get the list of the files that are going to be emptied by running only the first part of the command, up to but not including the | .

find / -maxdepth 1 -xdev -type f|xargs grep -l 'string'| xargs perl -pi -e 's/.*\n//g'

上面的命令甚至会删除文件中的换行符。如果要保留新行,只删除每行中的内容,请使用以下内容:

find / -maxdepth 1 -xdev -type f|xargs grep -l 'string'| xargs perl -pi -e 's/.//g'

One way:

$ for file in $(find / -maxdepth 1 -xdev -type f  -exec grep -li stringtofind '{}' \;)
> do
>   > $file
> done

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM