1

I'm using the following command to get the most recent file in a directory

/usr/bin/find /home/user1/folder1/ -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | cut -f5 -d"/"

This returns only the file name not the entire path.

I then want to copy the file I found into another folder, so I append the following to the previous find command:

 -exec cp {} /home/user2/folder2 \;

So the full command looks like this:

 /usr/bin/find /home/user1/folder1/ -type f -printf '%T@ %p\n' | sort -n | tail -1 | cut -f2- -d" " | cut -f5 -d"/ -exec cp {} /home/user2/folder2 \;

But this returns

cut: invalid option -- 'e'

What am I doing wrong here?

  • 6
    -exec belongs together with find, you can't just tuck it on at the end of the pipeline like that. – Kusalananda Jan 18 at 22:10
  • I'm realizing that now. Is there a solution for this though to accomplish my objective? – user53029 Jan 18 at 22:37
2

Your command appears to have two issues, the first of which may not matter much in your case, but is nevertheless worth pointing out: (i) it is not generic in the sense that it will not be able to process arbitrary filenames, in particular filenames that contain newlines (i.e. \n), and (ii) as already noted by Kusalananda, the -exec option belongs to the find command, and can thus not be separated therefrom as you have tried.

Using the GNU utilities, these issues can be fixed with the following pipeline, which will find the most recent file in (or below) the directory /home/user1/folder1/ and copy it to /home/user2/folder2/:

find /home/user1/folder1/ -type f -printf '%T@ %p\0' 2>/dev/null |
sort -znk1,1 | tail -zn1 | cut -zf2- -d' '                       |
xargs -0 cp -t /home/user2/folder2/

As to issue (i): note the \0 at the end of the -printf format string, and the -z and -0 options to the various commands in the pipeline, which ensure that the identified filename is passed in a NUL-delimited fashion, and thus enable it to include blanks and/or newlines.

As to issue (ii): you can use the xargs command to collect arguments from stdin and to build a new commandline with them. Part of the trick here is to use the -t option to the cp command, to specify the target directory before providing any filename to be copied there, since xargs will build a commandline by appending any arguments it receives on stdin to a given command.

2

Using the zsh shell, assuming you want to copy the most recently modified file in the /home/user1/folder1 directory:

cp /home/user1/folder1/*(.om[1]) /home/user2/folder2

If zsh is not your interactive shell, then you may do

zsh -c 'cp /home/user1/folder1/*(.om[1]) /home/user2/folder2'

The pattern /home/user1/folder1/*(.om[1]) would expand to the name of the most recently modified regular file in the given directory. The *(.om[1]) at the end is what orders (o) the regular files (.) by modification time (m) and picks the first ([1]).

If you need to match hidden filenames, then use

zsh -c -4 'cp /home/user1/folder1/*(.om[1]) /home/user2/folder2'

(add the -4)

Would you need to additionally look into subdirectories, use

zsh -c -4 'cp /home/user1/folder1/**/*(.om[1]) /home/user2/folder2'

The shell globbing pattern ** in zsh matches across / in pathnames.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.