Le code
ls -1 > AllFilesPresent.txt
value=$(<AllFilesPresent.txt)
rm AllFilesPresent.txt
for val in $value; do
a une fonctionnalité essentiellement identique à celle de
for val in $(ls -1); do
Cela ne fonctionne pas en général. Il ne fonctionne pas si les noms de fichiers contiennent des espaces ou des caractères globaux, au moins. Voir Pièges de Bash #1 (for f in $(ls *.mp3)) . En outre, l'utilisation des données de sortie de la ls
dans les programmes. Il ne convient qu'à une utilisation interactive. Voir aussi Pourquoi ne pas analyser la sortie de ls(1) .
Il existe une alternative correcte, totalement sûre, beaucoup plus courte et rapide :
for val in *; do
La solution complète à votre question est la suivante :
shopt -s nullglob
for file in Result*.RData; do
[[ -f $file && -s $file ]] && printf '%s\n' "$file"
done >CompletedJobs.txt
shopt -s nullglob
empêche les motifs globaux de se transformer en (ce qui équivaut à) des déchets s'ils ne correspondent à aucun fichier.
- J'ai remplacé
val
avec le plus significatif (pour moi en tout cas) file
.
- En
Result*.RData
fait en sorte que la boucle ne traite que les fichiers qui correspondent à ce motif.
- J'ai ajouté un
-f $file
pour éviter de traiter tout ce qui n'est pas un fichier (répertoires, fifos, ...) et qui pourrait traîner dans les parages. Il autorise toujours les liens symboliques vers les fichiers. Il se peut que vous ne souhaitiez pas cela. Vous pouvez ajouter un ! -L $file &&
au début de l'expression du test si vous souhaitez exclure les liens symboliques.
- J'ai remplacé
echo "$val"
con printf '%s\n' "$val"
parce que le code original ne fonctionne pas en général. Voir la réponse acceptée, et excellente, à Pourquoi printf est-il préférable à echo ? .
- J'ai déplacé la redirection vers
CompletedJobs.txt
à l'extérieur de la boucle, comme l'a suggéré @CharlesDuffy dans une commentaire .
- Notez que ce code ne fonctionnera pas si l'un des fichiers a des lignes nouvelles dans son nom (par exemple, créer un fichier avec
echo data > $'Result\n1.RData'
). C'est très rare, mais possible. La seule façon de stocker en toute sécurité des noms de fichiers généraux sans guillemets dans des fichiers est de les séparer par des caractères ASCII NUL (qui ne peuvent pas apparaître dans les noms de fichiers). Pour ce faire, remplacez le caractère printf ...
con printf '%s\0' "$file"
. Cela signifie que CompletedJobs.txt
n'est plus un fichier texte. Il faudrait également modifier tous les outils qui lisent le fichier.
Vous pouvez également le faire avec find
:
find . -maxdepth 1 -type f -name 'Result*.RData' -not -size 0 -printf '%P\n' >CompletedJobs.txt
- En
%P
avec le format -printf
supprime le premier ./
à partir des sorties, ce qui permet d'obtenir Result2.RData
au lieu de ./Result2.RData
(qui find
s'imprimerait par défaut, ou avec l'option -print
).
- Remplacer
\n
con \0
pour que la sortie soit sûre pour tout nom de fichier possible.