Sto cercando di utilizzare find
a echo 0
in alcuni file, ma apparentemente funziona solo con sh -c
:
find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' ;
Ma usando sh -c
con find -exec
mi fa sentire molto a disagio perché sospetto di citare problemi. Ci ho giocato un po' e a quanto pare i miei sospetti erano giustificati:
-
La mia configurazione di prova:
[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
-
Usando
find -exec
senzash -c
sembra funzionare senza problemi – non è necessario citare qui:[email protected] ~ % find findtest -type f -exec cat {} ; one two three
-
Ma quando utilizzo
sh -c
{}
sembra richiedere una sorta di citazione:[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
-
Le virgolette doppie funzionano fintanto che nessun nome di file contiene virgolette doppie:
[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
-
Le virgolette singole funzionano fintanto che nessun nome di file contiene virgolette singole:
[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
Non ho trovato una soluzione che funzioni in tutti i casi. C'è qualcosa che sto trascurando o sto usando sh -c
in find -exec
intrinsecamente pericoloso?
Risposta accettata:
Non incorporare mai {}
nel codice della shell! Ciò crea una vulnerabilità di iniezione dei comandi. Nota che per cat "{}"
, non si tratta solo del "
caratteri, ,
`
, $
sono anche un problema (considera ad esempio un file chiamato ./$(reboot)/accept_ra
)¹.
Qui, vorresti passare i nomi dei file come argomenti separati a sh
(non nel codice argomento) e il sh
script inline (il codice argomento) per farvi riferimento usando parametri posizionali:
find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} ;
Oppure, per evitare di eseguire un sh
per file:
find . -name accept_ra -exec sh -c 'for file do
echo 0 > "$file"; done' sh {} +
Lo stesso vale per xargs -I{}
o zsh
's zargs -I{}
. Non scrivere:
<list.txt xargs -I{} sh -c 'cmd > {}'
Che sarebbe una vulnerabilità di iniezione di comandi allo stesso modo di find
sopra, ma:
<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh
Che ha anche il vantaggio di evitare di eseguire un sh
per file e l'errore quando list.txt
non contiene alcun file.
Con zsh
's zargs
, probabilmente vorrai usare una funzione invece di invocare sh -c
:
do-it() cmd > $1
zargs ./*.txt -- do-it
Nota che in tutti gli esempi sopra il secondo sh
sopra va nello script inline $0
. Dovresti usare qualcosa di rilevante lì (come sh
o find-sh
), non cose come _
, -
, --
o la stringa vuota, come valore in $0
viene utilizzato per i messaggi di errore della shell:
$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} ;
inline-sh: ./accept_ra: Permission denied
GNU parallel
funziona in modo diverso. Con esso, non vuoi usare sh -c
come parallel
esegue già una shell e tenta di sostituire {}
con l'argomento citato nella sintassi corretta per la shell.
<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'