web-dev-qa-db-fra.com

Copier des fichiers d'un dossier à un autre mais avec un intervalle entre chaque fichier

Existe-t-il un moyen de copier des fichiers d'un dossier a vers un dossier b mais de laisser le processus s'interrompre une seconde entre chaque fichier? Je veux copier beaucoup de fichiers dans un dossier de contrôle, mais je sais par expérience que si je les copie tous en même temps (via le terminal cp ou l'interface graphique), mon plantage réel se bloquera ... Si je pouvais copier les fichiers avec un second intervalle entre eux, cela donnerait à torrent le temps de gérer les choses. Si je pouvais le faire à partir d'une commande, cela m'éviterait de le faire manuellement.

7
zotteken

Solutions à commande unique

Parmi les nombreuses options, y compris les boucles qui utilisent cp et sleep, nous pourrions opter pour find avec deux drapeaux -exec pour exécuter ces commandes exactes.

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

Ici les options sont:

  • ~/dir_1, le répertoire d'origine, par lequel find fonctionne.
  • -type f récupère uniquement les fichiers
  • -maxdepth 1 descends d'un niveau maximum dans l'arborescence de répertoires; empêche la descente dans les sous-répertoires
  • -exec cp {} ~/dir_2 \; copie le fichier en cours de traitement désigné par le paramètre {} dans ~/dir_2. Le \; indique que cp doit traiter un fichier à la fois au lieu de placer autant de fichiers que possible dans {}. La barre oblique inversée dans \; est nécessaire pour empêcher Shell d'interpréter cela de manière erronée en tant que terminateur de commande.
  • exec sleep 1 \; exécute sleep 1 pour chaque fichier en cours.

Si vous avez une liste de fichiers dans un fichier, vous pouvez faire:

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

Les options ici sont:

  • -I % désigne le symbole faisant référence à un fichier dans la commande
  • --arg-file=input.txt lire les arguments d'une commande à partir d'un fichier spécifique
  • sh -c 'cp % ~/dir_2/ ;sleep 1' exécuter /bin/sh avec les commandes fournies par -c '...' flag; % sera remplacé par nom de fichier.

Solutions de boucle

Vous pouvez utiliser une boucle for par exemple

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

Pour des raisons de clarté, ceci est formaté sur plusieurs lignes, mais cela fonctionne tout aussi bien comme une seule ligne. Vous pouvez aussi transformer cela en une fonction:

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

Et l'utiliser comme

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

Alternativement, si vous voulez copier uniquement certains fichiers, pas tout ce que * glob capture dans le répertoire, vous pouvez toujours utiliser le développement du chemin, quelque chose comme file{1..25}, ou avoir un fichier texte d'entrée, quelque chose comme ceci input.txt:

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

Et à partir de là, utilisez la structure while IFS= read -r line pour lire le fichier:

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

Avec parallel

Voici un parallel Install parallel solution, donnez les arguments à parallel avec ::: exactement comme avec cp ou utilisez une liste de fichiers:

parallel -j1 'cp {} /path/to/dir2/;sleep 1' ::: /path/to/dir1/* # or
parallel -j1 'cp {} /path/to/dir2/;sleep 1' :::: /path/to/file_list.txt

L'option -j indique à parallel de n'exécuter que le travail 1 à la fois plutôt que d'exécuter les travaux en parallèle. Les guillemets simples contiennent simplement le script dans lequel {} est remplacé par le travail en cours. file et ::: ou :::: introduisent respectivement la liste d'arguments ou le fichier. Voir man parallel pour beaucoup plus.

Avec find -exec

find fournit un moyen pratique d'exécuter des commandes sur les résultats, par exemple. pour copier chaque fichier .log dans et sous le répertoire actuel, procédez comme suit:

find -name "*.log" -exec sh -c 'cp "$0" /path/to/dir2/;sleep 1' "{}" \;
2
dessert