J'ai un script qui recherche dans tar tous les fichiers de plusieurs sous-dossiers et archives. 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 la sortie suivante
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 la variable FILE 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
avec 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 un autre moyen?
Mise à jour
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
La sortie que je reçois est
./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
IFS=$'\n'
avant la boucle `for de le faire analyser chaque ligneRéponses:
Utiliser
for
avecfind
est la mauvaise approche ici, voyez par exemple cet article sur la boîte de Pandore que vous ouvrez.L'approche recommandée consiste à utiliser
find
,while
etread
comme décrit ici . Voici un exemple qui devrait fonctionner pour vous:De cette façon, vous délimitez les noms de fichiers avec des caractères null (
\0
), cela signifie que la variation d'espace et d'autres caractères spéciaux ne poseront aucun problème.Afin de mettre à jour une archive avec les fichiers
find
localisés, vous pouvez transmettre sa sortie directement àtar
:Notez que vous ne devez pas différencier si l'archive existe ou non, vous la
tar
manipulerez avec discernement. Notez également l'utilisation de-printf
ici pour éviter d'inclure le./
bit dans l'archive.la source
./
tant que goudron../.tar tar: ./archive.tar: file is the archive; not dumped
if [[ "$FILE" == "./" ]]; then
continue
./
bit avec-printf
voir la réponse mise à jour. Cependant, cela ne devrait faire aucune différence s'il est inclus ou non, car il ne fait que référencer le répertoire actuel. J'ai également inclus unefind/tar
combinaison alternative que vous pouvez utiliser.sort
les résultats avant de les itérer, vous aurez besoinsort -z
du séparateur null.Essayez de citer la
for
boucle comme ceci:Sans guillemets, bash ne gère pas bien les espaces et les nouvelles lignes (
\n
) ...Essayez aussi de mettre
la source
comm
pour comparer des listes de fichiers triés et les noms de fichiers contenaient des espaces, bien que citant des variables cela ne fonctionnait pas. Ensuite, j'ai vu cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html et la solution consistant à définir $ IFS avec IFS = $ (echo -en "\ n \ b") fonctionnait pour moi.Cela fonctionne et est plus simple:
Nous remercions Rupa ( https://github.com/rupa/z ) pour cette réponse.
la source
En plus des citations appropriées, vous pouvez
find
utiliser un séparateur NULL, puis lire et traiter les résultats dans unewhile
boucle.Cela devrait gérer tous les noms de fichiers compatibles POSIX - voir
man find
la source
la source
J'ai fait quelque chose comme ça pour trouver des fichiers pouvant contenir des espaces.
Travaillé comme un charme :)
la source
La plupart des réponses sont interrompues s’il existe un caractère de nouvelle ligne dans le nom du fichier. J'utilise la bash depuis plus de 15 ans, mais uniquement interactive.
En Python, vous pouvez nous 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
la source
Je pense que vous serez peut-être mieux d'utiliser
find
l'option -exec de.Find exécute ensuite la commande à l'aide d'un appel système, de sorte que les espaces et les nouvelles lignes soient préservés (plutôt un tuyau qui nécessiterait la citation de caractères spéciaux). Notez que "tar -c" fonctionne que l'archive existe ou non, et que (du moins avec bash) ni {} ni + ne doivent être cités.
la source
Comme suggéré par minerz029, vous devez citer l’extension de la
find
commande. Vous devez également citer toutes les substitutions de$FILE
dans votre boucle.Notez que la
$()
syntaxe devrait être préférée à l'utilisation de backticks; voir cette question U & L . J'ai également supprimé le[[
mot clé et l' ai remplacé par la[
commande car il s'agit de POSIX.la source
[[
et[
, il semble que ce[[
soit plus récent et supporte plus de fonctionnalités telles que globbing et correspondance régulière.[[
est seulement dansbash
, cependant, passh
[[
soutient globbing. Selon le wiki de Greg , aucun déplacement ne se produit à l'intérieur[[
.[ "ab" == a? ] && echo "true"
alors[[ "ab" == a? ]] && echo "true"
a*
signifie "a suivi d'un nombre quelconque de caractères" plutôt que "tous les fichiers dont le nom commence para
un nombre quelconque de caractères après". Essayez[ ab = a* ] && echo true
contre[[ ab == a* ]] && echo true
.[[
toujours des expressions régulières tandis que[
ne le fait pas. Doit avoir eu confus