Eu vi alguns tópicos semelhantes, mas eles estão se referindo a não citar variáveis, o que eu sei que pode levar a resultados indesejados.
Eu vi este código e queria saber se seria possível injetar algo para ser executado quando esta linha de código for executada:
echo run after_bundle
Apenas uma nota extra sobre a boa resposta de @Kusalananda .
está bem porque nenhum dos caracteres nesses 3 argumentos¹ passou para
echo
conter caracteres que são especiais para o shell.E (o ponto extra que quero destacar aqui) não há nenhuma localidade do sistema onde esses bytes possam ser convertidos em caracteres especiais para o shell.
Todos esses caracteres estão no que o POSIX chama de conjunto de caracteres portáteis . Esses caracteres devem estar presentes e codificados da mesma forma em todos os conjuntos de caracteres em um sistema POSIX².
Portanto, essa linha de comando será interpretada da mesma forma, independentemente da localidade.
Agora, se começarmos a usar caracteres fora desse conjunto de caracteres portátil, é uma boa ideia colocá-los entre aspas mesmo que não sejam especiais para o shell, porque em outro locale, os bytes que os constituem podem ser interpretados como caracteres diferentes que podem se tornar especial para a casca. Observe que se você está usando
echo
ou qualquer outro comando, o problema não é,echo
mas como o shell analisa seu código.Por exemplo, em um UTF-8:
Isso
à
é codificado como 0xc3 0xa0. Agora, se você tiver essa linha de código em um script de shell e o script de shell for invocado por um usuário que usa uma localidade cujo conjunto de caracteres não é UTF-8, esses dois bytes podem criar caracteres muito diferentes.Por exemplo, em uma
fr_FR.ISO8859-15
localidade, uma localidade francesa típica usando o conjunto de caracteres padrão de byte único que abrange o idioma francês (o mesmo usado para a maioria dos idiomas da Europa Ocidental, incluindo o inglês), esse byte 0xc3 é interpretado como oÃ
caractere e 0xa0 como o não- quebrando o caractere de espaço.E em alguns sistemas como o NetBSD³, esse espaço sem quebra é considerado um caractere em branco (
isblank()
nele retorna true, é correspondido por[[:blank:]]
) e shells comobash
, portanto, o tratam como um delimitador de token em sua sintaxe.Isso significa que, em vez de executar
echo
como$'voil\xc3\xa0'
argumento, eles o executam$'voil\xc3'
como argumento, o que significa que não será impressovoilà
corretamente.Fica muito pior com conjuntos de caracteres chineses como BIG5, BIG5-HKSCS, GB18030, GBK, que têm muitos caracteres cuja codificação contém a mesma codificação que
|
,`
,\
(para citar o pior) (também aquele ridículo SJIS, também conhecido como Microsoft Kanji, exceto que é em¥
vez de\
, mas ainda é tratado como\
pela maioria das ferramentas, pois é codificado como 0x5c lá).Por exemplo, se em uma
zh_CN.gb18030
localidade chinesa, você escreve um script como:Esse script será gerado
詜 reboot
em uma localidade usando GB18030 ou GBK,唰 reboot
em uma localidade usando BIG5 ou BIG5-HKSCS, mas em uma localidade C usando ASCII ou uma localidade usando ISO8859-15 ou UTF-8, fará comreboot
que seja executado porque a codificação GB18030 of詜
é 0xd4 0x7c e 0x7c é a codificação de|
em ASCII, então acabamos executando:(que representa, no entanto, o byte 0xd4 é renderizado na localidade). Exemplo usando o menos prejudicial
uname
em vez dereboot
:(
uname
foi executado).Portanto, meu conselho seria citar todas as strings que contêm caracteres fora do conjunto de caracteres portátil.
No entanto, observe que, como a codificação de
\
e`
é encontrada na codificação de alguns desses caracteres, é melhor não usar\
ou"..."
ou$'...'
(dentro dos quais`
e/ou\
ainda são especiais), mas,'...'
em vez disso, citar caracteres fora do conjunto de caracteres portátil.Não tenho conhecimento de nenhum sistema que tenha uma localidade em que o conjunto de caracteres tenha qualquer caractere (além
'
dele, é claro) cuja codificação contenha a codificação de'
, portanto, esses'...'
devem ser definitivamente os mais seguros.Observe que vários shells também oferecem suporte a uma
$'\uXXXX'
notação para expressar caracteres com base em seu ponto de código Unicode. Em shells comozsh
ebash
, o caractere é inserido codificado no conjunto de caracteres do local (embora possa causar comportamentos inesperados se esse conjunto de caracteres não tiver esse caractere). Isso permite que você evite inserir caracteres não-ASCII em seu código shell.Então acima:
Ou:
(com a ressalva de que pode interromper o script quando executado em locais que não possuem esses caracteres).
Ou melhor, pois
\
também é especial paraecho
(ou pelo menos algumasecho
implementações, pelo menos as compatíveis com Unix):(observe que
\
também é especial no primeiro argumento paraprintf
, portanto, caracteres não ASCII também devem ser evitados, caso possam conter a codificação de\
).Observe que você também pode fazer:
(isso seria um exagero, mas poderia lhe dar alguma tranquilidade se você não tiver certeza de quais personagens estão no conjunto de caracteres portátil)
Certifique-se também de nunca usar a
`...`
forma antiga de substituição de comando (que introduz outro nível de processamento de barra invertida), mas use -a$(...)
.¹ tecnicamente,
echo
também é passado como argumento para oecho
utilitário (para dizer como foi invocado), é oargv[0]
eargc
é 3, embora na maioria dos shells hoje em diaecho
seja embutido,exec()
de modo que um/bin/echo
arquivo com uma lista de 3 argumentos seja simulado pelo Concha. Também é comum considerar a lista de argumentos como começando com o segundo (argv[1]
toargv[argc - 1]
), pois é sobre eles que os comandos agem principalmente.² uma exceção notável a isso sendo a
ja_JP.SJIS
localidade ridícula dos sistemas FreeBSD cujo conjunto de caracteres não possui nenhum caractere\
nem~
!³ observe que, embora muitos sistemas (FreeBSD, Solaris, mas não os GNU) considerem U+00A0 como um
[[:blank:]]
em localidades UTF-8, poucos o fazem em outras localidades como as que usam ISO8859-15, possivelmente para evitar esse tipo de problema.Para o caso específico
citação não é necessária. Nenhuma citação é necessária porque o argumento to
echo
são strings estáticas que não contêm expansões de variáveis ou substituições de comandos, etc. Elas são "apenas duas palavras" (e como Stéphane aponta , elas são adicionalmente construídas a partir do conjunto de caracteres portátil ).O "perigo" surge quando você lida com dados variáveis que o shell pode expandir ou interpretar. Nesses casos, deve-se tomar cuidado para que o shell faça a coisa certa e que o resultado seja o pretendido.
As duas perguntas a seguir contêm informações relevantes sobre isso:
echo
às vezes é usado para "proteger" comandos potencialmente prejudiciais em respostas neste site. Por exemplo, posso mostrar como remover arquivos ou mover arquivos para um novo destino usandoou
Isso produziria comandos no terminal em vez de realmente remover ou renomear arquivos. O usuário pode então inspecionar os comandos, decidir se eles parecem ok, removê-los
echo
e executá-los novamente.Seu comando
echo run after_bundle
pode ser uma instrução para o usuário ou pode ser um trecho de código "comentado" que é muito perigoso para ser executado sem saber as consequências.Usando
echo
assim, é preciso saber o que o comando modificado faz e deve-se garantir que o comando modificado seja realmente seguro (possivelmente não seria se contivesse redirecionamentos e usá-lo em um pipeline não funcionasse, etc.)