Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linux command output as a parameter of another command

I would like to pass the output list of elements of a command as a parameter of another command. I have found some other pages:

  • How to display the output of a Linux command on stdout and also pipe it to another command?
  • Use output of bash command (with pipe) as a parameter for another command

but they seem to be more complex.

I just would like to copy a file to every result of a call to the Linux find command.

What is wrong here?:

find . -name myFile 2>&1 | cp /home/myuser/myFile $1

Thanks

like image 915
Luis Andrés García Avatar asked Nov 05 '12 16:11

Luis Andrés García


3 Answers

This is what you want:

find . -name myFile -exec cp /home/myuser/myFile {} ';'

A breakdown / explanation of this:

  • find: invoking the find command
  • .: start search from current working directory.
  • Since no depth flags are specified, this will search recursively for all subfolders
  • -name myFile: find files with the explicit name myFile
  • -exec: for the search results, perform additional commands with them
  • cp /home/myuser/myFile {}: copies /home/myuser/myFile to overwrite each result returned by find to ; think of {} as where each search result goes.
  • ';': used to separate different commands to be run after find
like image 144
sampson-chen Avatar answered Sep 28 '22 02:09

sampson-chen


There are a couple of ways to solve this, depending on whether you need to worry about files with spaces or other special characters in their names.

If none of the filenames have spaces or special characters (they consist only of letters, numbers, dashes, and underscores), then the following is a simple solution that will work. You can use $(command) to execute a command, and substitute the results into the arguments of another command. The shell will split the result on spaces, tabs, or newlines, and for assign each value to $f in turn, and run the command on each value.

for f in $(find . -name myFile)
do
    cp something $f
done

If you do have spaces or tabs, you could use find's -exec option. You pass -exec command args, putting {} where you want the filename to be substituted, and ending the arguments with a ;. You need to quote the {} and ; so that the shell doesn't interpret them.

find . -name myFile -exec cp something "{}" \;

Sometimes -exec is not sufficient. For example, in this question, they wanted to use Bash parameter expansion to compute the filename. In order to do that, you need to pass -exec bash -c 'your command', but then you will run into quoting problems with the {} substitution. To solve this, you can use -print0 from find to print the results delimited with null characters (which are invalid in filenames), and pipe it to a while read loop that splits parameters on nulls:

find . -name myFile -print0 | (while read -d $'\0' f; do
    cp something "$f"
  done)
like image 39
Brian Campbell Avatar answered Sep 28 '22 01:09

Brian Campbell


The pipe will send the output of one program to the input of another. cp does not read from its input stream at the terminal, it merely uses the arguments on the command line.

You want to either use xargs with the pipe or find's exec argument instead of pipes.

find . -name myFile 2>&1 | xargs -I {} cp /home/myuser/myFile {}

Note: option -I {} defines {} as the place holder you could alternatively use someother placeholder if it conflicts with command to be executed.

like image 29
Brian Cain Avatar answered Sep 28 '22 03:09

Brian Cain