LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   grep and copy in one line (https://www.linuxquestions.org/questions/linux-newbie-8/grep-and-copy-in-one-line-4175602675/)

fanoflq 03-27-2017 10:22 PM

grep and copy in one line
 
Code:

~ $ grep -lri hello ~/dir0
/home/user1/dir0/hello1
/home/user1/dir0/hello2
/home/user1/dir0/hello3

Code:

~ $ grep -lri hello ~/dir0 | xargs cp -t ~/hellofilesfromdir0/
~ $ ls ~/hellofilesfromdir0/
hello1  hello2  hello3

I rather not remember using the t option for cp.
Is there another way to copy files found by grep like maybe
in the form below with outputs from grep going into
a placeholder {}
.
But this form does not works since it is not allowed!
Code:

~ $ grep -lri hello ~/dir0 | xargs cp {} ~/hellofilesfromdir0/

Is it also possible to do internal file search and copy without xargs, grep and cp?

syg00 03-28-2017 01:17 AM

Quote:

Originally Posted by fanoflq (Post 5689073)
But this form does not works since it is not allowed!
Code:

~ $ grep -lri hello ~/dir0 | xargs cp {} ~/hellofilesfromdir0/

Try
Code:

~ $ grep -lri hello ~/dir0 | xargs -I {} cp {} ~/hellofilesfromdir0/
Quote:

Is it also possible to do internal file search and copy without xargs, grep and cp?
Awk, perl, python, ... start coding.

ondoho 03-28-2017 02:02 AM

i think i'd rather use a miniscript "oneliner" instead of pipes.
something like this (pseudo bash, not tested):
Code:

for i in grep something; do cp $i $i.new ; done
see, all in 1 line! :D

MadeInGermany 03-28-2017 02:08 AM

cp has a -t option that works nicely with xargs and find -exec
Code:

grep -lri hello ~/dir0 | xargs cp -t ~/hellofilesfromdir0

pan64 03-28-2017 02:30 AM

probably:
cp -t <targetdir> $(grep ...)

fanoflq 03-28-2017 07:40 AM

Quote:

Originally Posted by ondoho (Post 5689134)
i think i'd rather use a miniscript "oneliner" instead of pipes.
something like this (pseudo bash, not tested):
Code:

for i in grep something; do cp $i $i.new ; done
see, all in 1 line! :D

This works.

Code:

~/dir0 $ ls ~/hellofilesfromdir0/
~/dir0 $ for i in $(grep -ilr  "hello" ~/dir0) ; do cp $i ~/hellofilesfromdir0/; done
~/dir0 $ ls ~/hellofilesfromdir0/
hello1  hello2  hello3


MadeInGermany 03-28-2017 10:46 AM

find -exec safely handles special file names like "two words.txt"
Code:

find ~/dir0 -type f -exec grep -qi hello {} \; -exec ln -t ~/hellofilesfromdir0 {} +
Further cp is replaced by an efficient ln (that increases the link count but only works within the file system; otherwise consider symlinks aka ln -s).

fanoflq 03-28-2017 01:11 PM

Quote:

Originally Posted by MadeInGermany (Post 5689270)
find -exec safely handles special file names like "two words.txt"
Code:

find ~/dir0 -type f -exec grep -qi hello {} \; -exec ln -t ~/hellofilesfromdir0 {} +
Further cp is replaced by an efficient ln (that increases the link count but only works within the file system; otherwise consider symlinks aka ln -s).

Your command works. Thank you.

When grep output is silent, where does its result go in the shell?
What shell symbol(s) hold those grep outputs?

I am not able to parse this:
Code:

-exec ln -t ~/hellofilesfromdir0 {} +
The braces in last exec command, {}, seems to imply it is
a placeholder for output of grep.

I did not know {} is a catch all for silent grep output. Or is it?
I am not able to find information in bash on this form of usage.
Then there is the plus, +, symbol at the end.
How does {} + interact?

What man page has this information?
Man bash does not explain much about exec.
Thank you.

MadeInGermany 03-28-2017 02:34 PM

The grep -q passes nothing but the exit status. A zero(="positive") exit status lets find continue with the next -exec
find substitutes each {} with the actual pathname.
{} + collects the arguments and calls the binary (here: cp or ln) with the maximum of arguments, just like xargs (without -l) does.
The first {} ends with \; because we immediately need the exit status for the current argument(=pathname).
The correct man page is
Code:

man find

fanoflq 03-28-2017 03:03 PM

Quote:

Originally Posted by MadeInGermany (Post 5689390)
The grep -q passes nothing but the exit status. A zero(="positive") exit status lets find continue with the next -exec
find substitutes each {} with the actual pathname.
{} + collects the arguments and calls the binary (here: cp or ln) with the maximum of arguments, just like xargs (without -l) does.
The first {} ends with \; because we immediately need the exit status for the current argument(=pathname).
The correct man page is
Code:

man find

Thank you.


All times are GMT -5. The time now is 01:19 AM.