简体   繁体   中英

Linux: Copy most recent directories (names have spaces)

I am using Linux and I have a directory structure as follows:

- RootFolder
  * DirectoryA
    * * Directory(X) [1]
    * * Directory Y
    * * DirectoryZ
 * DirectoryB

Note the special characters such as brackets, square brackets and spaces.

In practice, DirectoryA has a lot more subdirectories, but for the purpose of this example, let's say that I want to copy the 2 most recently created directories (with contents) from DirectoryA to DirectoryB.

My first attempt at this was to cd to RootFolder and run the following command:

ls -lt DirectoryA | head -2 | awk '{print "cp -r " $9 " DirectoryB/"$9 | sh

This failed because of special characters in various subdirectories and returned:

cp: can't stat Directory
cp: can't stat Directory(X)

Can someone advise on how to modify my command to work with spaces and special characters?

Quoting helps:

ls -t DirectoryA | head -2 | awk '{print "cp -vr \"DirectoryA/" $0 "\" DirectoryB/" }' |sh

I added a -v option to show what it does:

`DirectoryA/DirectoryZ' -> `DirectoryB/DirectoryZ'
`DirectoryA/Directory Y' -> `DirectoryB/Directory Y'

However, you would run into problems if the filenames contain double quotes or if they contain characters which ls does not represent except as question-marks.

As alternative, you can do the whole job using , with the help of built-in module File::Spec::Functions , that handles files and their paths, and external File::Copy::Recursive , that you will need to install from CPAN or similar, and copies directories recursively:

perl -MFile::Spec::Functions=catfile,catdir,splitdir -MFile::Copy::Recursive=rcopy -E ' 
    $dest = catdir(($ARGV[0], $ARGV[2]));
    $orig = catdir(($ARGV[0], $ARGV[1]));
    opendir $dh, $orig or die;
    for $f ( 
            sort { (stat $b)[9] <=> (stat $a)[9] } 
            grep { -d $_ and $_ !~ m/\.\.?$/ } 
            map { catfile $orig, $_ } 
            readdir $dh)[0..1] ) {

        rcopy($f, catdir $dest, (splitdir $f)[-1]) or die $!;
    }
' /your/path/to/RootFolder DirectoryA DirectoryB

It accepts three arguments, the first one is the path to your RootFolder , the second one the from , and the last one the to . The grep filters out non-directory files and special entries, and the sort checks its modification time, the slice [0..1] only gets the two most recent based in the modification time.

It worked in my test but if it does not match exactly for you, I hope it is near the finish line so you can give it a boost to it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM