Snažím se použít find na echo 0 do některých souborů, ale zřejmě to funguje pouze s sh -c :
find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' ;
Ale pomocí sh -c pomocí find -exec cítím se velmi neklidně, protože mám podezření na problémy s citováním. Trochu jsem si s tím pohrál a zřejmě mé podezření bylo oprávněné:
-
Moje testovací nastavení:
[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 -
Pomocí
find -execbezsh -cZdá se, že funguje bez problémů – zde není třeba citovat:[email protected] ~ % find findtest -type f -exec cat {} ; one two three -
Ale když používám
sh -c{}Zdá se, že vyžaduje nějaký druh citace:[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 -
Dvojité uvozovky fungují, pokud žádný název souboru neobsahuje uvozovky:
[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 -
Jednoduché uvozovky fungují, pokud žádný název souboru neobsahuje jednoduché uvozovky:
[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
Nenašel jsem řešení, které by fungovalo ve všech případech. Je něco, co přehlížím, nebo používám sh -c v find -exec ze své podstaty nebezpečné?
Přijatá odpověď:
Nikdy nevkládejte {} v kódu shellu! To vytváří zranitelnost příkazového vkládání. Všimněte si, že pro cat "{}" , není to jen o " znaků, , ` , $ jsou také problémem (uvažte například soubor s názvem ./$(reboot)/accept_ra )¹.
Zde byste chtěli předat názvy souborů jako samostatné argumenty do sh (není v kódu argument) a sh vložený skript (kód argument), abyste na ně odkazovali pomocí pozičních parametrů:
find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} ;
Nebo, abyste se vyhnuli spuštění jednoho sh na soubor:
find . -name accept_ra -exec sh -c 'for file do
echo 0 > "$file"; done' sh {} +
Totéž platí pro xargs -I{} nebo zsh 's zargs -I{} . Nepište:
<list.txt xargs -I{} sh -c 'cmd > {}'
Což by byla zranitelnost vkládání příkazů stejným způsobem jako u find výše, ale:
<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh
Což má také tu výhodu, že se vyhnete spuštění jednoho sh na soubor a chyba při list.txt neobsahuje žádný soubor.
Pomocí zsh 's zargs , pravděpodobně budete chtít použít funkci místo volání sh -c :
do-it() cmd > $1
zargs ./*.txt -- do-it
Všimněte si, že ve všech příkladech výše je druhý sh výše přejde do $0 vloženého skriptu . Měli byste tam použít něco relevantního (například sh nebo find-sh ), ne věci jako _ , - , -- nebo prázdný řetězec jako hodnotu v $0 se používá pro chybové zprávy shellu:
$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} ;
inline-sh: ./accept_ra: Permission denied
GNU parallel funguje jinak. S ním ne chcete použít sh -c jako parallel již spouští shell a pokouší se nahradit {} s argumentem citovaným ve správné syntaxi pro shell.
<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'