mv: Can't Stat Aucun fichier ou répertoire de ce type dans le script shell

16

J'ai écrit un script pour déplacer certains fichiers d'un dossier vers un autre dossier mais j'ai eu l'erreur suivante, j'ai vérifié 2 dossiers et j'ai remarqué que pour 1 dossier il y avait de tels fichiers et un autre il n'y en avait pas, mais pourquoi tous montraient "mv ne peut pas stat Pas de tels fichiers ou répertoire "

    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.42.17.124_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/195.113.161.13_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.199.61.205_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.51.218.235_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/213.73.40.105_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/41.225.7.4_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/83.230.127.122_tcp.folder/data/*': No such file or directory
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/
    129.88.70.226   132.187.230.1    138.96.116.22   155.185.54.250   192.38.109.144  193.136.227.163  193.175.135.61  195.113.161.13  83.230.127.122
    130.104.72.200  132.227.62.122   147.83.29.232   156.17.10.52     192.42.43.22    193.137.173.218  193.205.215.74  212.199.61.205
    131.130.69.164  132.252.152.194  148.81.140.193  157.181.175.249  192.43.193.71   193.144.21.131   193.226.19.30   212.51.218.235
    131.188.44.102  134.151.255.180  152.66.245.162  160.78.253.31    193.1.170.136   193.145.46.243   194.199.68.165  213.73.40.105
    131.254.208.10  138.48.3.203     152.81.47.4     192.114.4.3      193.136.166.56  193.166.160.98   194.42.17.124   41.225.7.4

le script est:

    list=`ls dest_folder`
    cd dest_folder
    cwd=`pwd`
    for folder in $list;do
            mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
    done

Je l'ai couru dedans /home/esolve/project/capture/tcp_50x50/

misteryes
la source
1
Veuillez montrer les parties pertinentes du script.
Mat
J'ai mis à jour ma question et ajouté le script, merci!
misteryes
Devez-vous ajouter un -rau mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAmateur
il n'y a pas d' -roption pourmv
misteryes

Réponses:

25
mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Les guillemets ( ') empêchent le shell de faire un globbing. Le *est passé littéralement à la mvcommande, qui échoue car il ne trouve pas les fichiers appelés *dans les répertoires indiqués.

Changez ceci en:

mv "${cwd}/${folder}/data"/* "${cwd}/${folder}"

(Double guillemets pour éviter les problèmes si vous avez un nom de répertoire avec des espaces dedans. En *dehors des guillemets.)

Vous obtiendrez toujours les erreurs pour les répertoires vides. (Même type de raison: si le fichier ne trouve pas de correspondance pour le modèle, il transmet le modèle lui-même comme argument à la commande.)

Tapis
la source
Les guillemets doubles ont du sens, mais pourquoi dois-je les mettre en *dehors des guillemets?
Sibbs Gambling
Si vous voulez qu'il soit étendu, vous en avez besoin en dehors de @SibbsGambling
Mat
8

Il y a plusieurs problèmes avec votre code:

list=`ls dest_folder`

Vous stockez la sortie de lssans les caractères de fin de ligne dans $list. lsaffiche la liste des noms de fichiers séparés par des caractères de nouvelle ligne. newlineest un caractère aussi valide que n'importe quel autre dans un nom de fichier, de sorte que la sortie ne peut pas être utilisée de manière fiable. Par exemple, la lssortie d'un répertoire qui contient aet best la même que celle d'un répertoire qui contient un fichier appelé a<newline>b.

 cd dest_folder

Vous ne vérifiez pas l'échec de cette commande. En général, vous devez vérifier l'état de sortie des commandes, mais c'est particulièrement vrai cd, car les autres commandes supposent que vous êtes dans ce nouveau répertoire, ce qui pourrait avoir des conséquences dramatiques lorsque vous ne l'êtes pas.

cwd=`pwd`

Les shells POSIX conservent déjà le (un) chemin vers le répertoire courant dans la $PWDvariable, donc vous ne devriez pas avoir besoin de l'utiliser pwdici (en particulier dans le cas général car la substitution de commande supprimerait les caractères de fin de ligne du chemin). En outre, mvaccepte les chemins relatifs afin que vous n'ayez pas besoin de créer le chemin absolu.

for folder in $list;do

Laisser une variable sans guillemets est l' opérateur split + glob dans les shells. C'est-à-dire que le contenu de la variable est divisé (sur les séparateurs mentionnés dans $IFSavec des règles spéciales pour les espaces blancs), et chaque élément résultant de ce fractionnement est recherché pour les caractères génériques afin qu'ils puissent être développés dans la liste des fichiers correspondants.

Ici, vous voulez le fractionnement, mais uniquement sur les caractères de nouvelle ligne, et vous ne voulez pas le globbing, vous devez donc le désactiver:

 IFS='
 '; set -f
 for folder in $list
   mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Encore une fois, laisser une variable sans guillemets est l' opérateur split + glob . Ici, vous ne voulez ni l'un ni l'autre, vous devez donc citer ces variables.

Comme déjà mentionné, les caractères génériques ne sont développés que lorsqu'ils ne sont pas cités, vous devez les *supprimer des guillemets. Si vous avez désactivé la globalisation plus tôt avec set -f, vous devez la rétablir set +favant d'appeler cette commande.

Une bien meilleure façon de l'écrire serait:

cd dest_folder &&
  for folder in */;do
    mv -- "${folder}data/"* "$folder"
  done

Quelques notes cependant:

  • Cela exclura les dossiers cachés et ne déplacera pas les fichiers cachés des datadossiers.
  • Nous ne vérifions pas si les fichiers sont remplacés dans le processus (vous pouvez ajouter l' -ioption à mv).
  • En utilisant */, nous bouclons uniquement sur les répertoires , mais cela inclut également les liens symboliques vers les répertoires. Si vous préférez ne pas, vous devez ajouter un [ -L "${folder%/}" ] && continueà l'intérieur de la boucle.
  • S'il n'y a pas de dossier non caché, il */se développera sur lui-même, vous obtiendrez donc un message d'erreur mvindiquant qu'il ne trouve pas de fichier appelé */data/*. De même, s'il n'y a aucun fichier non caché dans l'un des dossiers, vous obtiendrez un message d'erreur qui that-folder/data/*n'existe pas.
Stéphane Chazelas
la source