How do I copy the latest file from one directory to another?
Solution 1
Run this:
cp -p "`ls -dtr1 "$SRC_DIR"/* | tail -1`" "$DEST_DIR"
Here, ls -d
gives the absolute path.
In your command, as ls
is not returning absolute paths, you must run that from the source directory to get the file copied. As you have run it from some other directory that does not have the file, the error No such file or directory
being shown.
Also as you have spaces in the path we need to quote ls -dtr1 /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/* | tail -1
so that shell does not do word splitting on the output of it.
Solution 2
As others have already noticed, there are two problems with your approach. They have nothing to do with .zip
vs .sh
files, but with the names and locations of the files.
You need to put double quotes around command substitution. Otherwise they break at space characters. See Why does my shell script choke on whitespace or other special characters? for more details.
Furthermore the ls
command outputs just the base name of the file, without the directory part. cp
therefore only sees the base name and has no idea that you meant files in a different directory. One way to fix this is to switch to the desired directory first.
cd /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/
cp -p -- "`ls -tr | tail -n1`" ../Backup1/
If you want just the latest zip file and not the latest file whatever it is:
cd /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/
cp -p -- "`ls -dtr -- *.zip | tail -n1`" ../Backup1/
This will fail with a strange error message if the directory is empty or if there is a file name containing newlines or characters that are not printable in the current locale but these are relatively rare circumstances.
The option -d
is a bit of additional safety in case there is a subdirectory whose name matches *.zip
. You don't need the option -1
, its effect is automatic when the output of ls
is redirected to another command.
Alternatively, you can use zsh which makes this nice and easy thanks to its glob qualifiers.
cp -p /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/*(om[1]) /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Backup1/
Solution 3
It's because it depends from where you execute your cp
. In your example, ls -tr1 /Users/Me/Whatever
will return only website3.zip
. If you run your cp
from /tmp
, then it will try to find the file /tmp/website3.zip
.
To let ls
display the full path, you should use the wildcard *
.
Depending on what you want, it may be useful to specify -d
option to not let ls
list the content of all sub-directories:
$ ls -tr1d /Users/Me/Whatever
...
website3.zip
$ ls -tr1d /Users/Me/Whatever/*
...
/Users/Me/Whatever/website3.zip
However, be careful in case the last modified entry is a directory. In this case, cp
won't copy it if you omit the -R
option.
If your files always have a .zip
extension you may consider:
$ ls -tr1d /Users/Me/Whatever/*.zip
You may also get an error if your directory is empty. Why don't you script something like that:
#!/bin/bash
MY_DIR="/Users/Me/Documents/Coffi Work/FTP Backup Shell Script/Original/"
DEST="/Users/Me/Documents/Coffi Work/FTP Backup Shell Script/Backup1/"
FILEEXT="zip"
NEWEST=`ls -tr1d "${MY_DIR}/"*.${FILEEXT} 2>/dev/null | tail -1`
if [ -z "${NEWEST}" ] ; then
echo "No file to copy"
exit 1
elif [ -d "${NEWEST}" ] ; then
echo "The most recent entry is a directory"
exit 1
else
echo "Copying ${NEWEST}"
cp -p "${NEWEST}" "${DEST}"
fi
Related videos on Youtube
![smj2393](https://i.stack.imgur.com/wsbCv.jpg?s=256&g=1)
smj2393
Updated on September 18, 2022Comments
-
smj2393 almost 2 years
I have 3 zip files in a directory. I want to copy the most recent version to a backup directory.
My code works fine for
.sh
and other files, but not for.zip
. Is there something else I have to do?cp -p `ls -tr1 /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/| tail -1` /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Backup1/
It says:
cp: website3.zip: No such file or directory
-
smj2393 about 9 yearsHi, sorry I am very new to Unix command line. But yes if I run the command from inside
/Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/
it works. How can I fix this? -
heemayl about 9 yearsPlease check my answer.
-
Scott - Слава Україні about 9 yearsThis question has nothing to do with zip or zip files. You should have done enough research (i.e., trying to solve your problem by yourself) to see that that the file extension was not the factor that determined whether the command worked. And you should write question titles, and choose tags, that correspond better to what the question is actually about.
-
smj2393 about 9 years@Gilles how is this a duplicate???
-
Gilles 'SO- stop being evil' about 9 yearsSorry, I'd only noticed the missing quotes issue, not the missing path part. Reopening.
-
-
smj2393 about 9 yearsIf I run
ls -dtr1
it outputs.
It is a One not a L yes? -
heemayl about 9 yearsYes, notice a
*
after the path (/Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/*
). -
smj2393 about 9 yearsWhat does the * do? Sorry I am very new to this.
-
heemayl about 9 yearsThe shell will expand
*
to all files in that directory..Please read shell globbing to get more idea.. -
smj2393 about 9 yearsAlso what is the 2>/dev/null?
-
smj2393 about 9 yearsI get the error:
cp: Work/FTP: No such file or directory cp: Backup: No such file or directory cp: Shell: No such file or directory cp: Script/Original/dfds.zip: No such file or directory
-
smj2393 about 9 yearsBut if I CD in terminal to this directory works and if I then ls it displays all the zip files.
-
heemayl about 9 yearsAs your file path contains spaces shell is doing word splitting..we need to use quote..Run
cp -p "
ls -dtr1 /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/* | tail -1" /Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Backup1/
-
heemayl about 9 yearsCheck my edits on the answer..
-
apaul about 9 years@smj2393 this is the same problem that you commented on @heemayl answer: your path contains spaces. The first time the space is well escaped with
`, but when you got the output of
ls, spaces remain un-escaped. If it's possible, avoid spaces in the name of your files or directories. If you can't, add double-quotes on the
cp` line:cp -p "${NEWEST}" "${DEST}"
(I made an edit) -
apaul about 9 years@smj2393
2>/dev/null
redirects error message in/dev/null
, sols
won't output something like "no such file or directory" -
smj2393 about 9 yearsIt doesn't work with this
"${MYDIR}"
either :/ I am trying to tidy the code up with variables. -
apaul about 9 years@smj2393 yeah, dealing with spaces may be tricky (if you use double quotes, you have to let spaces un-escaped). Look at my edited script: I've removed backslashes from
MY_DIR
andDEST
, but I've added double-quotes quite everywhere. -
smj2393 about 9 yearsYes, I have tried the same, but now it says the most recent file is a directory. When there are only Zip files in the folder?
-
smj2393 about 9 yearsI would avoid using spaces, but i'm writing a script for an old web server which has uses spaces :/
-
apaul about 9 yearsLet us continue this discussion in chat.
-
smj2393 about 9 yearsSorry Paul, I was unavailable last night.
-
smj2393 about 9 yearsThank you Gilles. I have it working now, it takes a bit of getting used to this new syntax. I am used to HTML5 etc. Thanks though.