Como fazer com que o argumento da função/script Bash seja copiado completamente para a variável, pois '
(e algum outro caractere) não pode reter estar na variável?
por exemplo
m() {
v="$@"
echo "$v"
}
$ m let it be 'foo' bar
let it be foo bar
A ajuda sincera é apreciada, obrigado antes.
A coisa a notar aqui é que quando você executa, por exemplo
o programa
m
não obtém a linha de comando inteira, mas o shell analisa a linha de comando primeiro, processando aspas, expansões de variáveis e coisas assim. O resultado final que vai para o comando é mais como um array de strings separadas, que nesse caso seria [let
,it
,be
,foo bar
].Da mesma forma, em
m
apenas veria [Bond, James Matthew Bond
], e não teria ideia das variáveis e cotações envolvidas.Isso significa que um programa regular não tem como chegar à linha de entrada bruta.
Existem soluções alternativas para o zsh com manipuladores pré-executivos em Qualquer shell em que as expansões são desativadas sem escapar ou citar? e zsh: alias ou shell function para apenas ecoar sua linha de comando, incluindo caracteres de controle do shell , mas não acho que vi um para o Bash.
O mais próximo que você obtém é o
DEBUG
trap, que vê o comando a ser executado antes de expansões, processamento de cotações e redirecionamentos. No entanto, não está completo, pois vê apenas um único comando simples de cada vez. Os comentários serão removidos antes de vê-los, e um sem aspas;
,&
,|
,&&
,||
ou(
()
pelo menos) ainda será analisado.De qualquer forma, podemos tentar:
O script usa o
DEBUG
trap para detectar comandos que começam com@
, pega a próxima "palavra" separada por espaço como um comando a ser executado e passa o restante como um único argumento para ele. Retornar1
do manipulador de trap diz ao shell para não executar o comando da maneira normal, evitando uma provável mensagem de erro e bloqueando a execução de quaisquer expansões incorporadas (isso requerextdebug
configuração).A saída é algo assim, mostrando que o
date
após o ponto e vírgula é executado e que o parêntese quebra a sintaxe:Para ser honesto, isso é um pouco nojento, as restrições com os caracteres especiais são bastante arbitrárias, e não garanto que o script não tenha outros problemas também.
Em geral, se você está planejando isso para algum tipo de uso em produção, sugiro reconsiderar a estrutura do programa e passar a string por um arquivo ou, por exemplo, um here-doc, dependendo do que você está fazendo.
Um here-doc torna relativamente fácil alimentar uma string bruta, embora passe pelo comando
stdin
:Que imprime
Com a string delimitadora here-doc entre aspas (em
<<'EOF'
), isso permite que você coloque texto e caracteres arbitrários sem a necessidade de se preocupar com aspas. (Além da própria string delimitadora, é claro, mas você pode usar uma gerada aleatoriamente em vez deEOF
.)Você precisa convencer o shell de que uma aspa simples é uma parte do valor da variável assim:
O shell está interpretando as
'
aspas antes que a função as veja e fará o mesmo com eg"
e\
. Você pode escapar deles com\
, por exemploO problema aqui é que você está passando a entrada sem aspas. Como resultado, o
'
está sendo consumido pelo shell antes de chamar sua função. O mesmo aconteceria se você tivesse usado um"
, e também falharia se você tivesse usado caracteres globbing como*
ou?
:A solução mais limpa, pelo menos para mim, é sempre passar sua entrada citada. Isso protegerá quaisquer caracteres com significado especial do shell e, assim, garantirá que eles sejam passados inalterados para sua função: