Isso não está relacionado a citar, mas sim ao processamento de argumentos.
Considere o exemplo arriscado:
find -exec sh -c "something {}" \;
-
Isso é analisado pelo shell e dividido em seis palavras:
find
,-exec
,sh
,-c
,something {}
(sem citações mais),;
. Não há nada para expandir. O shell executafind
com essas seis palavras como argumentos. -
Quando
find
encontra algo para processar, digamosfoo; rm -rf $HOME
, substitui{}
porfoo; rm -rf $HOME
e executash
com os argumentossh
,-c
esomething foo; rm -rf $HOME
. -
sh
agora vê-c
e, como resultado, analisasomething foo; rm -rf $HOME
( o primeiro argumento não opcional ) e executa o resultado.
Agora, considere a variante mais segura:
find -exec sh -c 'something "$@"' sh {} \;
-
O shell executa
find
com os argumentosfind
,-exec
,sh
,-c
,something "$@"
,sh
,{}
,;
. -
Agora, quando
find
encontrafoo; rm -rf $HOME
, substitui{}
novamente e executash
com os argumentossh
,-c
,something "$@"
,sh
,foo; rm -rf $HOME
. -
sh
vê-c
e analisasomething "$@"
como o comando a ser executado esh
efoo; rm -rf $HOME
como os parâmetros posicionais ( iniciando em$0
), expande"$@"
parafoo; rm -rf $HOME
como um único valor e executasomething
com o único argumentofoo; rm -rf $HOME
.
Você pode ver isso usando printf
. Crie um novo diretório, digite-o e execute
touch "hello; echo pwned"
Executando a primeira variante da seguinte forma
find -exec sh -c "printf \"Argument: %s\n\" {}" \;
produz
Argument: .
Argument: ./hello
pwned
enquanto a segunda variante é executada como
find -exec sh -c 'printf "Argument: %s\n" "$@"' sh {} \;
produz
Argument: .
Argument: ./hello; echo pwned