Ubuntu – Copy files from one folder to another but have an interval between each file

command linecopyscripts

Is there a way to copy files from folder a to folder b but have the process pause for a second between each file?
I want to copy a whole lot of files to a watch folder but I know from experience that if I copy all of them at once (either through terminal cp or GUI) it will make my rtorrent crash…
If i could copy the files with a second interval between them, that would give rtorrent the time to handle things. If I could do that from one command, that would save me from doing it one by one manually.

Best Answer

Single command solutions

Among many options, including loops that make use of cp and sleep, we could opt for find with two -exec flags to run those exact commands.

find ~/dir_1/ -type f -maxdepth 1  -exec cp {} ~/dir_2 \;  -exec sleep 1   \;

Here the options are:

  • ~/dir_1 , the origin directory, through which find works.
  • -type f get only files
  • -maxdepth 1 descend down 1 level maximum in the directory tree; prevents descending into subdirectories
  • -exec cp {} ~/dir_2 \; copy the currently processed file designated by {} parameter to ~/dir_2. The \; designates for cp to process single file at a time instead of tacking as many files as possible into {}. The backslash in \; is necessary to prevent shell from misinterpreting that as command terminator.
  • exec sleep 1 \; executes sleep 1 per each current file.

If you have a list of files in a file, you can do:

xargs -I % --arg-file=input.txt sh -c 'cp % ~/dir_2/ ;sleep 1'

Options here are:

  • -I % designates the symbol which refers to file within the command
  • --arg-file=input.txt read arguments to command from specific file
  • sh -c 'cp % ~/dir_2/ ;sleep 1' execute /bin/sh with provided commands by -c '...' flag; % will be substituted with filename.

Loop solutions

You could use a for loop for instance

for f in "/path/to/folder_1"/*; do
    cp "$f"  "/path/to/folder_2/"
    sleep 1
done

For clarity, this is formatted on multiple lines, but this works as a single line just as well. You could also turn this into a function:

delaycp(){
    for f in "$1"/*; do
        cp "$f"  "$2"/
        sleep 1
    done
}

And use it as

delaycp "/path/to/folder1" "/path/to/folder2"

Alternatively, if you want to copy only certain files, not everyting that * glob captures in the directory, you could always make use of pathname expansion, something like file{1..25}, or have an input text file, something like this input.txt:

/path/to/folder_1/file1
/path/to/folder_1/file2
/path/to/folder_1/file3

And from there make use of while IFS= read -r line structure to read the file:

while IFS= read -r line || [ -n "$line" ]; do
    cp "$line" "/path/to/folder_2/${line##*/}"
    sleep 1
done < input.txt