简体   繁体   中英

About the usage of linux command “xargs”

I have some file like

love.txt  
loveyou.txt 

in directory useful ; I want to copy this file to directory /tmp .

I use this command:

find ./useful/ -name "love*" | xargs cp /tmp/

but is doesn't work, just says:

cp: target `./useful/loveyou.txt' is not a directory

when I use this command:

 find ./useful/ -name "love*" | xargs -i cp {} /tmp/

it works fine,

I want to know why the second works, and more about the usage of -i cp {} .

xargs puts the words coming from the standard input to the end of the argument list of the given command. The first form therefore creates

cp /tmp/ ./useful/love.txt ./useful/loveyou.txt

Which does not work, because there are more than 2 arguments and the last one is not a directory.

The -i option tells xargs to process one file at a time, though, replacing {} with its name, so it is equivalent to

cp ./useful/love.txt    /tmp/
cp ./useful/loveyou.txt /tmp/

Which clearly works well.

When using the xargs -i command, {} is substituted with each element you find. So, in your case, for both "loveyou.txt" and "love.txt", the following command will be run:

cp ./useful/loveyou.txt /tmp/
cp ./useful/love.txt /tmp/

if you omit the {} , all the elements you find will automatically be inserted at the end of the command, so, you will execute the nonsensical command:

cp /tmp/ ./useful/loveyou.txt ./useful/love.txt

The first example will do this:

cp /tmp/ love.txt loveyou.txt

Which can't be done, since they attempt to copy the directory /tmp and the file love.txt to the file loveyou.txt .

In the second example, -i tells xargs to replace every instance of {} with the argument, so it will do:

cp love.txt /tmp/
cp loveyou.txt /tmp/

xargs appends the values fed in as a stream to the end of the command - it does not run the command once per input value. If you want the same command run multiple times - that is what the -i cp {} syntax is for.

This works well for commands which accept a list of arguments at the end (eg grep) - unfortunately cp is not one of those - it considers the arguments you pass in as directories to copy to, which explains the 'is not a directory' error.

find ./useful/ -name "love*" | xargs cp -t /tmp/

你可以这样避免xargs:

find ./useful/ -name "love*" -exec sh -c 'cp "$@" /tmp' sh {} +

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