How do I copy the latest file from one directory to another?

54,344

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
Share:
54,344

Related videos on Youtube

smj2393
Author by

smj2393

Updated on September 18, 2022

Comments

  • smj2393
    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
      smj2393 about 9 years
      Hi, 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
      heemayl about 9 years
      Please check my answer.
    • Scott - Слава Україні
      Scott - Слава Україні about 9 years
      This 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
      smj2393 about 9 years
      @Gilles how is this a duplicate???
    • Gilles 'SO- stop being evil'
      Gilles 'SO- stop being evil' about 9 years
      Sorry, I'd only noticed the missing quotes issue, not the missing path part. Reopening.
  • smj2393
    smj2393 about 9 years
    If I run ls -dtr1 it outputs . It is a One not a L yes?
  • heemayl
    heemayl about 9 years
    Yes, notice a * after the path (/Users/Me/Documents/Coffi\ Work/FTP\ Backup\ Shell\ Script/Original/*).
  • smj2393
    smj2393 about 9 years
    What does the * do? Sorry I am very new to this.
  • heemayl
    heemayl about 9 years
    The shell will expand * to all files in that directory..Please read shell globbing to get more idea..
  • smj2393
    smj2393 about 9 years
    Also what is the 2>/dev/null?
  • smj2393
    smj2393 about 9 years
    I 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
    smj2393 about 9 years
    But if I CD in terminal to this directory works and if I then ls it displays all the zip files.
  • heemayl
    heemayl about 9 years
    As 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
    heemayl about 9 years
    Check my edits on the answer..
  • apaul
    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
    apaul about 9 years
    @smj2393 2>/dev/null redirects error message in /dev/null, so ls won't output something like "no such file or directory"
  • smj2393
    smj2393 about 9 years
    It doesn't work with this "${MYDIR}" either :/ I am trying to tidy the code up with variables.
  • apaul
    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 and DEST, but I've added double-quotes quite everywhere.
  • smj2393
    smj2393 about 9 years
    Yes, 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
    smj2393 about 9 years
    I would avoid using spaces, but i'm writing a script for an old web server which has uses spaces :/
  • apaul
    apaul about 9 years
  • smj2393
    smj2393 about 9 years
    Sorry Paul, I was unavailable last night.
  • smj2393
    smj2393 about 9 years
    Thank 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.