J'essaie d'utiliser find
à echo 0
dans certains fichiers, mais apparemment cela ne fonctionne qu'avec sh -c
:
find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' ;
Mais en utilisant sh -c
avec find -exec
me met très mal à l'aise parce que je soupçonne des problèmes de citation. J'ai un peu bidouillé et apparemment mes soupçons étaient justifiés :
-
Ma configuration de test :
[email protected] ~ % cd findtest [email protected] ~/findtest % echo one > file with spaces [email protected] ~/findtest % echo two > file with 'single quotes' [email protected] ~/findtest % echo three > file with "double quotes" [email protected] ~/findtest % ll insgesamt 12K -rw-rw-r-- 1 martin martin 6 Sep 17 12:01 file with "double quotes" -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with 'single quotes' -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with spaces
-
Utilisation de
find -exec
sanssh -c
semble fonctionner sans problème - aucune citation nécessaire ici :[email protected] ~ % find findtest -type f -exec cat {} ; one two three
-
Mais quand j'utilise
sh -c
{}
semble nécessiter une sorte de citation :[email protected] ~ % LANG=C find findtest -type f -exec sh -c 'cat {}' ; cat: findtest/file: No such file or directory cat: with: No such file or directory cat: spaces: No such file or directory cat: findtest/file: No such file or directory cat: with: No such file or directory cat: single quotes: No such file or directory cat: findtest/file: No such file or directory cat: with: No such file or directory cat: double quotes: No such file or directory
-
Les guillemets doubles fonctionnent tant qu'aucun nom de fichier ne contient de guillemets doubles :
[email protected] ~ % LANG=C find findtest -type f -exec sh -c 'cat "{}"' ; one two cat: findtest/file with double: No such file or directory cat: quotes: No such file or directory
-
Les guillemets simples fonctionnent tant qu'aucun nom de fichier ne contient de guillemets simples :
[email protected] ~ % LANG=C find findtest -type f -exec sh -c "cat '{}'" ; one cat: findtest/file with single: No such file or directory cat: quotes: No such file or directory three
Je n'ai pas trouvé de solution qui fonctionne dans tous les cas. Y a-t-il quelque chose que je néglige ou utilise sh -c
dans find -exec
intrinsèquement dangereux ?
Réponse acceptée :
Ne jamais intégrer {}
dans le code shell ! Cela crée une vulnérabilité d'injection de commande. Notez que pour cat "{}"
, il ne s'agit pas seulement de "
caractères, ,
`
, $
sont également un problème (considérez par exemple un fichier appelé ./$(reboot)/accept_ra
)¹.
Ici, vous voudriez passer les noms de fichiers en tant qu'arguments séparés à sh
(pas dans le code argument), et le sh
script en ligne (le code argument) pour y faire référence à l'aide de paramètres positionnels :
find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} ;
Ou, pour éviter d'exécuter un sh
par fichier :
find . -name accept_ra -exec sh -c 'for file do
echo 0 > "$file"; done' sh {} +
Il en va de même pour xargs -I{}
ou zsh
's zargs -I{}
. N'écrivez pas :
<list.txt xargs -I{} sh -c 'cmd > {}'
Ce qui serait une vulnérabilité d'injection de commande de la même manière qu'avec find
ci-dessus, mais :
<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh
Ce qui a aussi l'avantage d'éviter d'exécuter un sh
par fichier et l'erreur lorsque list.txt
ne contient aucun fichier.
Avec zsh
zargs
, vous voudrez probablement utiliser une fonction plutôt que d'invoquer sh -c
:
do-it() cmd > $1
zargs ./*.txt -- do-it
Notez que dans tous les exemples ci-dessus le second sh
ci-dessus va dans le $0
du script en ligne . Vous devriez utiliser quelque chose de pertinent ici (comme sh
ou find-sh
), pas des choses comme _
, -
, --
ou la chaîne vide, comme valeur dans $0
est utilisé pour les messages d'erreur du shell :
$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} ;
inline-sh: ./accept_ra: Permission denied
GNU parallel
fonctionne différemment. Avec elle, vous ne faites pas voulez utiliser sh -c
comme parallel
exécute déjà un shell et essaie de remplacer {}
avec l'argument cité dans la bonne syntaxe pour le shell.
<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'