I’m using fd, an alternative to the Unix native find, to find a list of files and copy them to a different location, using xargs. On Unix, we use cp to copy the files, but the command is silent.
I don’t know which files cp will copy. Maybe I could use echo to log the files?

How can I pass multiple shell commands to xargs?

Previous command:

fd --changed-within 1hour -0 | xargs -I cp {} /new/location/
  • fd -0 --changed-within: find all files changed within a time frame, separate results by null character
  • |: pipe previous command as stdin to the next command
  • xargs -I cp {} /new/location/: takes the input from previous command (fd) and uses cp to copy the files; {} is a placeholder

What does not work:

fd --changed-within 1hour -0 | xargs -I cp {} /new/location/ | xargs -I echo {}

What does work:

fd --changed-within 1hour -0 | xargs -0 sh -c \
'for arg do echo "$arg"; cp "$arg" /new/location/; done' _
  • xargs -0: use null as separating character (useful for files that contain whitespace)
  • sh -c: read commands from next string
  • 'for arg do echo "$arg"; cp "$arg" /new/location/; done' _: loop over each input and first use echo to log, then cp to new location
  • _ is a placeholder for $0, such that other data values added by xargs become $1 and onward, which happens to be the default set of values a for loop iterates over.

This is shell magic to me!

I found the solution on StackOverflow, where you can also find a more detailed explanation.