Já vi alguns tópicos semelhantes, mas eles estão se referindo a não citar variáveis, o que eu sei que poderia levar a resultados indesejados.
Eu vi esse código e queria saber se seria possível injetar algo a ser executado quando essa linha de código for executada:
echo run after_bundle
Respostas:
Para o caso específico
não é necessário citar. Nenhuma citação é necessária porque o argumento
echo
são cadeias estáticas que não contêm expansões variáveis ou substituições de comandos etc. Elas são "apenas duas palavras" (e, como Stéphane aponta , elas são construídas adicionalmente a partir do conjunto de caracteres portáteis ).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 correta e que o resultado seja o que se pretende.
As duas perguntas a seguir contêm informações relevantes sobre isso:
echo
às vezes é usado para "proteger" comandos potencialmente prejudiciais nas respostas deste 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 que eles parecem bem, remover o
echo
e executar novamente.Seu comando
echo run after_bundle
pode ser uma instrução para o usuário ou um código "comentado" que é muito perigoso para ser executado sem conhecer as consequências.Usando
echo
assim, é necessário saber o que o comando modificado faz e é preciso garantir que o comando modificado seja realmente seguro (potencialmente não seria se contivesse redirecionamentos e usá-lo em um pipeline não funcione etc.)fonte
echo rm "first file.txt" "second file.txt"
é de alguma forma diferenteecho rm "first" "file.txt" "second" "file.txt"
, a saída de ambos é a mesma. Se você deseja gerar um comando shell como saída, deve-se usarprintf '%q ' rm "first file.txt" "second file.txt"; echo
ou algo equivalente que gere novamente a citação sintática que seja avaliada comoargv
passada.sh
não é exatamente um padrão incomum, e ver as pessoas perguntarem "por quefoo
funciona quando eu o executo em uma linha de comando, mas esse script que emite a string exataecho
na frente da linha não? " acontece o tempo todo aqui. Mais precisamente, a saída de depuração não é útil se ocultar seus erros - e se seus erros estiverem relacionados à citação,echo
eles não serão revelados.Apenas uma nota extra em cima da boa resposta de @ Kusalananda .
é bom porque nenhum dos caracteres nesses 3 argumentos¹ passou para
echo
conter caracteres especiais para o shell.E (o ponto extra que quero destacar aqui) não há localidade do sistema em que esses bytes possam ser traduzidos para caracteres especiais para o shell.
Todos esses caracteres estão no que o POSIX chama de conjunto de caracteres portátil . 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 citá-los, mesmo que não sejam especiais para o shell, porque em outro local, os bytes que os constituem podem ser interpretados como caracteres diferentes que podem se tornar especial para a concha. Observe que, independentemente de você estar usando
echo
ou qualquer outro comando, o problema não é comecho
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 use um código de idioma cujo conjunto de caracteres não seja UTF-8, esses dois bytes poderão gerar caracteres muito diferentes.Por exemplo, em um
fr_FR.ISO8859-15
código de idioma, um código de idioma típico do francês que usa o conjunto de caracteres de byte padrão que cobre o idioma francês (o mesmo usado para a maioria dos idiomas da Europa Ocidental, incluindo o inglês), que 0xc3 byte é interpretado como oÃ
caractere e 0xa0 como não quebrando o caráter do espaço.E em alguns sistemas como o NetBSD³, esse espaço sem quebra é considerado como um caractere em branco (
isblank()
ele retorna verdadeiro, é correspondido por[[:blank:]]
) e shells como,bash
portanto, o tratam como um delimitador de token em sua sintaxe.Isso significa que em vez de correr
echo
com$'voil\xc3\xa0'
como argumento, eles executá-lo com$'voil\xc3'
como argumento, o que significa que não será impressovoilà
corretamente.Ele fica muito pior com conjuntos de caracteres chineses como BIG5, BIG5-HKSCS, GB18030, GBK que têm muitos personagens cujas codificação contém a mesma codificação como
|
,`
,\
(para citar o pior) (também que SJIS ridícula, aka Microsoft Kanji, excepto em¥
vez de\
, mas ainda tratado como\
pela maioria das ferramentas, pois está codificado como 0x5c).Por exemplo, se em um
zh_CN.gb18030
local chinês, você escreve um script como:Esse script será produzido
詜 reboot
em um唰 reboot
código de idioma usando GB18030 ou GBK, em um código de idioma usando BIG5 ou BIG5-HKSCS, mas em um código de idioma C usando ASCII ou em um código de idioma usando ISO8859-15 ou UTF-8, seráreboot
executado porque a codificação GB18030 de詜
é 0xd4 0x7c e 0x7c é a codificação|
em ASCII, portanto, acabamos executando:(que representa no entanto o byte 0xd4 é renderizado no código do idioma). Exemplo usando o menos prejudicial em
uname
vez dereboot
:(
uname
foi executado).Portanto, meu conselho seria citar todas as strings que contêm caracteres fora do conjunto de caracteres portáteis.
No entanto, observe que, como a codificação de
\
e`
é encontrada na codificação de alguns desses caracteres, é melhor não usar\
or"..."
ou$'...'
(dentro do qual`
e / ou\
ainda são especiais), mas'...'
sim citar caracteres fora do conjunto de caracteres portátil.Não conheço nenhum sistema que possua uma localidade em que o conjunto de caracteres possua qualquer caractere (que não seja
'
ele próprio, é claro) cuja codificação contenha a codificação de'
, portanto esses'...'
devem ser definitivamente os mais seguros.Observe que vários shells também suportam 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 da localidade (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 no seu código de shell.Então acima:
Ou:
(com a ressalva, ele pode interromper o script quando executado em locais que não possuem esses caracteres).
Ou melhor, já que
\
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 são melhor evitados no caso de conterem a codificação de\
).Observe que você também pode fazer:
(isso seria um exagero, mas poderia lhe dar alguma tranqüilidade se você não tiver certeza de quais caracteres estão no conjunto de caracteres portáteis)
Além disso, certifique-se de nunca usar a
`...`
forma antiga de substituição de comando (que introduz outro nível de processamento de barra invertida), mas use em$(...)
vez disso.¹ tecnicamente,
echo
também é passado como argumento para oecho
utilitário (para dizer como foi chamado), é oargv[0]
eargc
é 3, embora na maioria dos shells hoje em diaecho
esteja embutido, de modo queexec()
um/bin/echo
arquivo com uma lista de 3 argumentos seja simulado pelo Concha. Também é comum considerar a lista de argumentos como iniciando com o segundo (argv[1]
paraargv[argc - 1]
), pois é sobre isso que os comandos atuam principalmente.² uma exceção notável por ser o
ja_JP.SJIS
local ridículo dos sistemas FreeBSD cujo charset não tem\
nem~
caráter!³ observe que, embora muitos sistemas (FreeBSD, Solaris, e não os GNU) considerem U + 00A0 como um local
[[:blank:]]
UTF-8, poucos o fazem em outros locais como os que usam ISO8859-15, possivelmente para evitar esse tipo de problema.fonte
echo
...", apenas conto 2 argumentos sendo passados para o comandoecho
, os argumentos que posso contar sãorun
eafter_bundle
, gostaria de explicar como você contou e chegou a 3 argumentos?echo
). Veja(exec -a foo /bin/echo --help)
em um sistema GNU e com o shell GNU como passar um primeiro argumento arbitrário para o/bin/echo
utilitário.$0
Parâmetros meio e posicionais em conchas.iconv
nas quaisESC
é convertido em'
. Tente (como exemplo):printf '\x1b'|iconv -f utf8 -t IBM-937|xxd
'
. Tenteprintf '\u2804' | iconv -f utf8 -t BRF | xxd
. Existem codificações nas quais existem muitos pontos de código que se tornam'
. Cerca de 8695 pontos de código no UCS-4 se tornam'
. Tenteprintf '\U627' | iconv -cf utf-8 -t UCS-4
. Várias codificações (37) convertem o caractere 0x127 em a'
. Tenteprintf '\U127' | iconv -cf utf8 -t UCS2 |xxd