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 -execsenzash -csembra 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 > {}'