53 votes

Noms de fichiers avec espaces rompant boucle for, commande find

J'ai un script qui recherche tous les fichiers dans plusieurs sous-dossiers et les archive en tar. Mon script est

for FILE in `find . -type f  -name '*.*'`
  do
if [[ ! -f archive.tar ]]; then

  tar -cpf archive.tar $FILE
else 
  tar -upf archive.tar $FILE 
fi
done

La commande find me donne le résultat suivant

find . -type f  -iname '*.*'
./F1/F1-2013-03-19 160413.csv
./F1/F1-2013-03-19 164411.csv
./F1-FAILED/F2/F1-2013-03-19 154412.csv
./F1-FAILED/F3/F1-2011-10-02 212910.csv
./F1-ARCHIVE/F1-2012-06-30 004408.csv
./F1-ARCHIVE/F1-2012-05-08 190408.csv

Mais le DOSSIER la variable ne stocke que la première partie du chemin ./F1/F1-2013-03-19 puis la partie suivante 160413.csv .

J'ai essayé d'utiliser read à l'aide d'une boucle "while",

while read `find . -type f  -iname '*.*'`;   do ls $REPLY; done

mais j'obtiens l'erreur suivante

bash: read: `./F1/F1-2013-03-19': not a valid identifier

Quelqu'un peut-il suggérer une autre solution ?

Update

Comme suggéré dans les réponses ci-dessous, j'ai mis à jour les scripts.

#!/bin/bash

INPUT_DIR=/usr/local/F1
cd $INPUT_DIR
for FILE in "$(find  . -type f -iname '*.*')"
do
archive=archive.tar

        if [ -f $archive ]; then
        tar uvf $archive "$FILE"
        else
        tar -cvf $archive "$FILE"
        fi
done

Le résultat que j'obtiens est le suivant

./test.sh
tar: ./F1/F1-2013-03-19 160413.csv\n./F1/F1-2013-03-19 164411.csv\n./F1/F1-2013-03-19 153413.csv\n./F1/F1-2013-03-19 154412.csv\n./F1/F1-2012-09-10 113409.csv\n./F1/F1-2013-03-19 152411.csv\n./.tar\n./F1-FAILED/F3/F1-2013-03-19 154412.csv\n./F1-FAILED/F3/F1-2013-03-19 170411.csv\n./F1-FAILED/F3/F1-2012-09-10 113409.csv\n./F1-FAILED/F2/F1-2011-10-03 113911.csv\n./F1-FAILED/F2/F1-2011-10-02 165908.csv\n./F1-FAILED/F2/F1-2011-10-02 212910.csv\n./F1-ARCHIVE/F1-2012-06-30 004408.csv\n./F1-ARCHIVE/F1-2011-08-17 133905.csv\n./F1-ARCHIVE/F1-2012-10-21 154410.csv\n./F1-ARCHIVE/F1-2012-05-08 190408.csv: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors

2voto

Scott B Points 21

J'ai fait quelque chose comme ça pour trouver les fichiers qui peuvent contenir des espaces.

IFS=$'\n'
for FILE in `/usr/bin/find $DST/shared -name *.nsf | grep -v bookmark.nsf | grep -v names.nsf`; do
    file $FILE | tee -a $LOG
done

Cela a fonctionné comme un charme :)

1voto

user2802945 Points 11
find . <find arguments> -print0 | xargs -0 grep <pattern>

0voto

Joseph R. Points 310

Comme l'a suggéré minerz029, vous devez citer l'expansion de la find commande. Vous devez également mettre entre guillemets toutes les substitutions de $FILE dans votre boucle.

for FILE in "$(find . -type f  -name '*.*')"
do
    if [ ! -f archive.tar ]; then
        tar -cpf archive.tar "$FILE"
    else 
        tar -upf archive.tar "$FILE" 
    fi
done

Il convient de noter que le $() doit être préférée à l'utilisation de barres obliques ; voir cette question U & L . J'ai également retiré le [[ et l'a remplacé par le mot-clé [ parce qu'elle est POSIX.

0voto

user42348 Points 780

La plupart des réponses ici se cassent la figure s'il y a un caractère de retour à la ligne dans le nom de fichier. J'utilise bash depuis plus de 15 ans, mais seulement en interactif.

En Python, vous pouvez utiliser os.walk() : http://docs.Python.org/2/library/os.html#os.walk

Et le module tarfile : http://docs.Python.org/2/library/tarfile.html#tar-examples

0voto

J'ai rencontré un problème similaire dans un script que j'ai utilisé pour convertir des fichiers audio. Les noms de fichiers contenaient des espaces, ce qui posait des problèmes pour les noms de fichiers convertis. Cette solution a fonctionné pour moi sous OSX, en utilisant zsh :

  1. Obtenez tous les fichiers à l'aide de find. Découpez la barre oblique et le point. Trier la sortie.
  2. Obtenir le nombre de tous les fichiers.
  3. Utiliser le comptage pour parcourir les fichiers en boucle
  4. Utiliser une combinaison de queue et de tête pour sélectionner les fichiers ligne par ligne (comme un curseur SQL).
  5. Traiter le dossier si nécessaire.

Comme je convertis des fichiers audio, je voulais utiliser les noms de fichiers originaux (y compris les espaces) pour les nouveaux fichiers audio convertis. Le script que j'ai utilisé inclut les paramètres FROM et TO pour spécifier les formats audio. Il effectue également quelques coupes supplémentaires dans la boucle pour supprimer l'extension. Comme je souhaitais uniquement obtenir le nom complet du fichier, j'ai jugé nécessaire de supprimer l'extension avant de le convertir à l'aide de la variable TO.

#!/bin/zsh

#  Convert all audio files in directory
#  audioconvert [original] [converted]

export FROM=$1
export TO=$2

export FILES=$(find . -name "*.$FROM" | cut -d "/" -f 2 | sort) 
export CNT=$(echo $FILES | wc -l)

while [ $CNT -gt 0 ];do
  export song=$(echo $FILES | tail -n $CNT | head -n 1) 
  export song_title=$(echo $song | cut -d . -f 1) 

  ffmpeg -i $song  $song_title.$TO

  let CNT=$CNT-1
done

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X