Si vous utilisez xargs -0 , vous devez le faire correspondre avec find -0
itsbruce
1
@ MichaelKjörling, aucune citation {} ne fait aucune différence. {} est développé par find, pas par le shell. Une amélioration serait de ne pas utiliser echoce qui étend les séquences d'échappement comme \b(au moins les conformes Unix echo).
Stéphane Chazelas
1
@sch Êtes-vous sûr? La findpage de manuel s'affiche find . -type f -exec file '{}' \;dans la EXAMPLESsection. Peut-être que certaines coquilles traiteront spécialement les accolades.
QuasarDonkey
1
Les citations ne nuisent pas mais ne font aucune différence. Tous '{}', \{\}, {}, "{}", '{'}sont complétés par le shell (quelle que soit Bourne shell-like) à un argument de constater que les deux personnages est « { » et « } ». Remplacez "find" par "echo find", ou printf '<%s>\n' findsi vous souhaitez revérifier.
Mais notez que les espaces ne sont pas le seul problème dans le code que vous avez donné. les caractères de tabulation, de nouvelle ligne et de caractère générique sont également un problème.
Avec
IFS='
'set-f
for i in $(find .-name '*.jpg');do echo "$i";done
Ensuite, seuls les caractères de nouvelle ligne posent problème.
Ce que vous avez mentionné est l'un des problèmes fondamentaux auxquels les gens sont confrontés lorsqu'ils essaient de lire les noms de fichiers. Parfois, les personnes ayant des connaissances limitées et ayant une conception erronée de la structure des fichiers et des dossiers ont tendance à oublier que " Sous UNIX, tout est un fichier ". Ils ne comprennent donc pas qu'ils doivent également gérer les espaces, car le nom de fichier peut être composé de 2 mots ou plus avec des espaces.
Solution: l' une des façons les plus connues de procéder consiste à effectuer une lecture claire .
Nous allons ici lire tous les fichiers présents et les conserver dans une variable, la prochaine fois lors du traitement souhaité, nous devrons simplement garder cette variable entre guillemets qui préservera les noms de fichiers avec des espaces. C'est l'un des moyens de base de le faire, cependant, les autres réponses fournies par les autres personnes ici fonctionnent tout aussi bien.
Ici, je lis les fichiers en leur donnant le chemin d'accès et tout ce que je lis, je les garde dans une variable I, que je citerai plus tard en le traitant pour conserver les espaces afin de le traiter correctement.
J'espère que cela vous aide d'une manière ou d'une autre.
"tout est un fichier" fait référence à autre chose. Votre solution est spécifique à GUN et ne résiste pas à la barre oblique inverse ou aux caractères de nouvelle ligne dans les noms de fichiers. Les boucles "while read" dans les shells (IMO) sont souvent une indication d'une mauvaise pratique de script shell.
Stéphane Chazelas
@sch: hein, et je pensais, ça va. Merci de l'avoir signalé, j'ai probablement besoin de l'examiner davantage.
The Dark Knight
désolé, je voulais dire "GNU", pas "GUN" ci-dessus (c'est la première fois que je réalise que ce sont des anagrammes BTW ...)
Stéphane Chazelas
1
Simplement avec findet bash:
find .-name '*.jpg'-exec bash -c '
echo "treating file $1 in bash, from path : ${1%/*}"
'--{} \;
De cette façon, nous utilisons $1en bash, comme dans un script de base, qui ouvrent de belles perspectives pour effectuer toutes les tâches avancées (ou non).
Un moyen plus efficace (pour éviter d'avoir à démarrer un nouveau bash pour chaque fichier):
find .-name '*.jpg'-exec bash -c 'for i do
echo "treating file $i in bash, from path : ${i%/*}"
done'--{}+
Bien que cela fonctionne dans zsh (d'où provient la fonctionnalité) et avec ksh93 (avec set -G), il ne devrait pas être utilisé dans bash car la version bash est fondamentalement cassée (tout comme GNU grep -r) car elle descend en liens symboliques vers des répertoires (équivalents à find -Lou zsh) ***/*.jpg). Notez également que contrairement à find, il supprimera les dotfiles et ne descendra pas dans les dotdirs (par défaut).
$i
? Je fais ça et ça marche bien. Y a-t-il un problème avec cette approche?Réponses:
La voie canonique est de faire
(remplacez
\;
par+
pour transmettre plusieurs fichiersecho
à la fois)ou (spécifique à GNU, bien que certains BSD l'aient également):
zsh:
la source
echo
ce qui étend les séquences d'échappement comme\b
(au moins les conformes Unixecho
).find
page de manuel s'affichefind . -type f -exec file '{}' \;
dans laEXAMPLES
section. Peut-être que certaines coquilles traiteront spécialement les accolades.'{}'
,\{\}
,{}
,"{}"
,'{'}
sont complétés par le shell (quelle que soit Bourne shell-like) à un argument de constater que les deux personnages est « { » et « } ». Remplacez "find" par "echo find", ouprintf '<%s>\n' find
si vous souhaitez revérifier.De meilleures réponses ont déjà été données.
Mais notez que les espaces ne sont pas le seul problème dans le code que vous avez donné. les caractères de tabulation, de nouvelle ligne et de caractère générique sont également un problème.
Avec
Ensuite, seuls les caractères de nouvelle ligne posent problème.
la source
Ce que vous avez mentionné est l'un des problèmes fondamentaux auxquels les gens sont confrontés lorsqu'ils essaient de lire les noms de fichiers. Parfois, les personnes ayant des connaissances limitées et ayant une conception erronée de la structure des fichiers et des dossiers ont tendance à oublier que " Sous UNIX, tout est un fichier ". Ils ne comprennent donc pas qu'ils doivent également gérer les espaces, car le nom de fichier peut être composé de 2 mots ou plus avec des espaces.
Solution: l' une des façons les plus connues de procéder consiste à effectuer une lecture claire .
Nous allons ici lire tous les fichiers présents et les conserver dans une variable, la prochaine fois lors du traitement souhaité, nous devrons simplement garder cette variable entre guillemets qui préservera les noms de fichiers avec des espaces. C'est l'un des moyens de base de le faire, cependant, les autres réponses fournies par les autres personnes ici fonctionnent tout aussi bien.
SCRIPT:
Ici, je lis les fichiers en leur donnant le chemin d'accès et tout ce que je lis, je les garde dans une variable I, que je citerai plus tard en le traitant pour conserver les espaces afin de le traiter correctement.
J'espère que cela vous aide d'une manière ou d'une autre.
la source
Simplement avec
find
etbash
:De cette façon, nous utilisons
$1
en bash, comme dans un script de base, qui ouvrent de belles perspectives pour effectuer toutes les tâches avancées (ou non).Un moyen plus efficace (pour éviter d'avoir à démarrer un nouveau bash pour chaque fichier):
la source
Dans la version récente de bash, vous pouvez utiliser l'
globstar
option:Pour les actions simples, vous pouvez même ignorer complètement la boucle:
la source
set -G
), il ne devrait pas être utilisé dans bash car la version bash est fondamentalement cassée (tout comme GNUgrep -r
) car elle descend en liens symboliques vers des répertoires (équivalents àfind -L
ou zsh)***/*.jpg
). Notez également que contrairement à find, il supprimera les dotfiles et ne descendra pas dans les dotdirs (par défaut).