A escolha é sua. Se você não citar $@
nenhum dos seus valores, sofrerá expansão e interpretação adicionais. Se você citar todos os argumentos passados, a função será reproduzida literalmente em sua expansão. Você nunca poderá manipular de forma confiável tokens de sintaxe de shell como &>|
e etc, de qualquer maneira, sem analisar os argumentos de qualquer maneira - e assim você terá as opções mais razoáveis de entregar sua função em um dos seguintes:
- Exatamente as palavras usadas na execução de um único comando simples com
"$@"
.
...ou...
- Uma versão adicional expandida e interpretada dos seus argumentos, que só são aplicados juntos como um simples comando
$@
.
Nenhuma das maneiras está errada se for intencional e se os efeitos do que você escolher forem bem compreendidos. Ambas as formas têm vantagens uma sobre a outra, embora as vantagens da segunda raramente sejam particularmente úteis. Ainda...
(run_this(){ $@; }; IFS=@ run_this 'ls@-dl@/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
... não é inútil , apenas raramente é de grande utilidade . E em um bash
shell, porque bash
, por padrão, não adere uma definição de variável ao seu ambiente, mesmo quando a definição é anexada à linha de comando de um built-in especial ou a uma função, o valor global de $IFS
não é afetado e sua declaração é local. apenas para a run_this()
chamada.
Similarmente:
(run_this(){ $@; }; set -f; run_this ls -l \*)
ls: cannot access *: No such file or directory
... o globbing também é configurável. As cotações servem a um propósito - não são à toa. Sem eles, a expansão do shell passa por uma interpretação extra - interpretação configurável . Ela costumava ser - com algumas muito antigas conchas - que $IFS
foi globalmente aplicadas a todos os de entrada, e não apenas expansões. De fato, as referidas conchas se comportaram da mesma run_this()
maneira que quebraram todas as palavras de entrada no valor de $IFS
. E assim, se o que você está procurando é que o comportamento shell muito antiga, então você deve usar run_this()
.
Não estou procurando por isso e estou bastante pressionado no momento para encontrar um exemplo útil para isso. Geralmente, prefiro que os comandos que meu shell execute sejam aqueles que digito nele. E assim, dada a escolha, eu quase sempre run_that()
. Exceto aquilo...
(run_that(){ "$@"; }; IFS=l run_that 'ls' '-ld' '/tmp')
drwxrwxrwt 22 root root 660 Dec 28 19:58 /tmp
Qualquer coisa pode ser citada. Os comandos serão executados entre aspas. Funciona porque, no momento em que o comando é realmente executado, todas as palavras de entrada já foram removidas entre aspas - que é o último estágio do processo de interpretação de entrada do shell. Portanto, a diferença entre 'ls'
e ls
só pode importar enquanto o shell estiver interpretando - e é por isso que a citação ls
garante que qualquer apelido nomeado ls
não seja substituído pela minha ls
palavra de comando citada . Fora isso, as únicas coisas que as aspas afetam são a delimitação de palavras (que é como e por que funciona a citação de espaço em branco de variável / entrada) e a interpretação de metacaracteres e palavras reservadas.
Então:
'for' f in ...
do :
done
bash: for: command not found
bash: do: unexpected token 'do'
bash: do: unexpected token 'done'
Você nunca será capaz de fazer isso com um run_this()
ou outro run_that()
.
Mas nomes de funções, ou $PATH
comandos, ou builtins serão executados entre aspas ou sem aspas, e é exatamente assim run_this()
e como run_that()
funciona em primeiro lugar. Você não poderá fazer nada de útil com $<>|&(){}
nenhum deles. Curto eval
, é.
(run_that(){ "$@"; }; run_that eval printf '"%s\n"' '"$@"')
eval
printf
"%s\n"
"$@"
Mas sem ele, você está limitado aos limites de um comando simples em virtude das aspas que você usa (mesmo quando não o faz, porque $@
age como uma cotação no início do processo quando o comando é analisado por metacaracteres) . A mesma restrição se aplica às atribuições e redirecionamentos da linha de comando, limitados à linha de comando da função. Mas isso não é grande coisa:
(run_that(){ "$@";}; echo hey | run_that cat)
hey
Eu poderia ter tão facilmente <
redirecionado a entrada ou >
saída lá como abri o tubo.
De qualquer forma, de uma maneira geral, não há um caminho certo ou errado aqui - cada um tem seus usos. Você deve escrever como pretende usá-lo e saber o que pretende fazer. Citações omitindo pode ter um propósito - caso contrário, não haveria ser citações em tudo - mas se você omiti-los por razões não relevantes para a sua finalidade, você está apenas escrevendo código ruim. Faça o que você quer dizer; Eu tento de qualquer maneira.
run_that
O comportamento de definitivamente é o que eu esperaria (e se houver um espaço no caminho para o comando?). Se você quisesse o outro comportamento, certamente o citaria no local da chamada onde sabe quais são os dados? Eu esperaria chamar essa função comorun_that ls -l
, que funciona da mesma maneira em qualquer versão. Existe um caso que fez você esperar diferente?