1

I’m looking for a way to copy a file to all Desktops directory of each user.

Something like:

cp myfile /home/*/Desktop/

I found a way to copy files to all home directories using xargs but it fails on the subdirectory.

2
  • 2
    The cp command looks fine. If the question is about a problem using xargs, you should edit the question to include both the command itself and its output (where it fails and maybe a line or two of its successes). Otherwise, the question lacks enough detail to be answerable (and is likely to be closed as unclear). Aug 29, 2019 at 9:35
  • Actually, as pointed out by msp9011’s answer, cp myfile /home/*/Desktop/ won’t work because the cp command only facilitates copying files to a single destination. Aug 29, 2019 at 15:52

2 Answers 2

3

Your code expands as:

cp myfile /home/user1/Desktop/ /home/user2/Desktop/ /home/user3/Desktop/ /home/user4/Desktop/ ... /home/userN/Desktop/

From man of cp:

Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

which means, it will try to copy "myfile /home/user1/Desktop/ /home/user2/Desktop/ /home/user3/Desktop/ /home/user4/Desktop/ ..." to /home/userN/Desktop/

it will throw an error because except "myfile" all other where directories...

try this,

UserS=($(awk -F':' '{ if ( $3 >= 500 ) print $1 }' /etc/passwd))
for i in ${UserS[@]}
do
    [ -d /home/"$i"/Desktop ] && cp myfile /home/"$i"/Desktop
done
2
  • This will work only if the total length of the for ... command line with the wildcard expanded is less than the maximum length of the shell command line. If there is a large number of users, it might go over the limit and cause a "command line too long" error without doing anything at all. In practice, this is unlikely to be a problem unless you have a huge number of users, since the command line length might be anything from 32k bytes on Cygwin to 200k bytes on modern Linuxes.
    – telcoM
    Aug 29, 2019 at 9:55
  • 1
    @telcoM Expanding a shell glob in for will not result in a "argument list too long" error as exec() is not called. That's only an issue when calling an external command with a great number of arguments.
    – Kusalananda
    Aug 29, 2019 at 10:29
0

Since cp only ever takes a single destination name, you would have to make it a loop and call copy the files individually:

for destdir in /home/*/Desktop/; do
    cp myfile "$destdir"
done

Using xargs here, as you suggest, would probably work, but would be cumbersome:

printf '%s\n' /home/*/Desktop/ | xargs -I {} cp myfile {}

This relies on the names of the subdirectories under /home not having newlines in them (but I know of no Unix that allows newlines in usernames).

It is conceivable that you'd also like to change the owner of the file to that of the owner of the corresponding Desktop directory.

You can do this conveniently with GNU chown (from coreutils) like so:

for destdir in /home/*/Desktop/; do
    cp myfile "$destdir" &&
    chown --reference="$destdir" "$destdir/myfile"
done

Doing that with xargs:

printf '%s\n' /home/*/Desktop/ | xargs -I {} sh -c 'cp myfile "$1" && chown --reference="$1" "$1/myfile"' sh {}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .