Atribuindo comando à variável sem alias

3

Eu acidentalmente descobri que no bash, podemos atribuir um comando a uma variável sem usar alias .

g=date
$g
Mon Jun 27 13:00:40 MYT 2016

Isso funciona. Aqui está outro exemplo:

jj="ping yahoo.com"
$jj
PING yahoo.com (98.138.253.109) 56(84) bytes of data.
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=1 ttl=41 time=347 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=2 ttl=41 time=345 ms
64 bytes from ir1.fp.vip.ne1.yahoo.com (98.138.253.109): icmp_seq=3 ttl=41 time=345 ms

Estou usando esta versão do bash bash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

Eu examinei stackexchange e tldp abs , mas não achamos que podemos fazer assim. Então, isso é um novo recurso do bash ou algo sendo negligenciado? Isto é considerado substituição de comandos ?

    
por sylye 27.06.2016 / 07:20

4 respostas

2

Esse é o comportamento esperado e está funcionando há muito tempo. É útil para criar comandos em scripts.

Digamos, por exemplo, que às vezes eu aplique a descompactação em alguma entrada antes de enviá-la para um pipeline (e a compressão na saída depois), mas às vezes não. Usando bash :

if (( use_compression == 1 )); then
   infilter='gzip -d -c'
   outfilter='gzip -c'
else
   infilter='cat'
   outfilter='cat'
fi

$infilter "$indatafile" | somepipeline | $outfilter >"$outdatafile"

É a substituição de comando? Não. "Substituição de comando" refere-se especificamente à substituição de $(...) ou da variante de retrocesso pelo conteúdo de sua saída.

Esta é a expansão de parâmetros , isto é, simplesmente substituindo os parâmetros pelos seus valores. Isso acontece antes que o comando seja realmente executado e é por isso que funciona.

Isso significa que coisas como as seguintes também funcionam na linha de comando:

$ decompress='gzip -d -c'
$ ${decompress/g/gun/} filename >unzippedfilename

(que executaria gunzip em vez de gzip )

EDITAR : Sobre aliases.

O manual bash diz:

For almost every purpose, aliases are superseded by shell functions.

... e eu concordo.

Os aliases são bons para coisas curtas como

alias ls="ls -F"

(esse é o único alias que eu tenho nas minhas próprias sessões de shell)

Você provavelmente não deseja usar expansões de parâmetros para comandos "aliasing" na linha de comando. Se não por qualquer outro motivo, é uma dor no pescoço para digitar. A expansão de parâmetro também não permite executar tarefas um pouco mais complexas, como pipelining.

Se você tem operações moderadamente complexas que está executando regularmente, use as funções do shell para elas.

Seguindo o exemplo da resposta aceita para a pergunta sobre U & L (com o link nos comentários abaixo):

alias my_File='ls -f | grep -v /'

Esse alias obviamente funciona, mas usando

my_File='ls -f | grep -v /'

não funcionará se você tentar usar $my_File como um comando na linha de comando (como explicado por que nesse segmento U & L).

Com uma função de shell, você também poderá fazer coisas como passar argumentos:

function my_File {
    ls -l "$@" | fgrep -v '/'
}

$ my_File -iF symlink
84416642 lrwxr-xr-x  1 kk  staff  4 Jun 27 09:03 symlink@ -> file
    
por 27.06.2016 / 08:24
3

No uso interativo, o shell lê as linhas de entrada do dispositivo terminal. Depois que uma linha é inserida, ela é analisada dividindo-se em tokens (palavras e operadores). Os tokens ou palavras são então expandidos ou resolvidos em uma ordem específica.

Observação: em geral, geralmente é melhor se referir à fonte canônica de informações, como documentação de projeto ou especificação do setor, sobre fontes de segunda mão, como o Guia avançado de script de script, tutoriais on-line, livros ou até mesmo o Stack Exchange: ). Essas fontes de segunda mão são úteis para introduzir e explicar conceitos em linguagem mais simples, mas geralmente não pretendem ser completas ou substituir a documentação oficial. As informações na fonte de segunda mão também podem estar desatualizadas.

Nesse caso, a especificação POSIX para analisar comandos simples afirma que

  1. The words that are not variable assignments or redirections shall be expanded. If any fields remain following their expansion, the first field shall be considered the command name and remaining fields are the arguments for the command.

O Seção de manual do Bash sobre expansão simples de comandos também afirma que

  1. The words that are not variable assignments or redirections are expanded (see Shell Expansions). If any words remain after expansion, the first word is taken to be the name of the command and the remaining words are the arguments.
    
por 27.06.2016 / 11:14
3

Isto não é substituição de comando, é uma substituição variável . Você não está atribuindo um comando a uma variável, você está atribuindo uma string. O comando é executado quando você usa a variável, não no momento da atribuição.

g=date armazena a string date na variável g . Se você executar echo "$g" , isso imprimirá o valor de g , ou seja, date (seguido por uma nova linha), porque o valor de g é passado para o comando echo como o primeiro argumento. Se você executar "$g" , isso colocará a string date na primeira posição do comando, então é o nome do comando.

Com $jj , um segundo fator entra em jogo. Como a expansão da variável está fora de aspas, o " operador split + glob " é aplicado ao valor. Nesse caso, isso significa que o valor de jj é dividido em duas palavras separadas por espaço. Assim, a palavra ping acaba na posição de comando e a palavra yahoo.com é o primeiro argumento.

    
por 28.06.2016 / 03:28
2

Ele está simplesmente usando variáveis de shell, um conceito que existe e funciona assim há décadas (sem exagero).

Quando você coloca uma variável em uma linha de comando, o shell a substitui e então executa o comando, então se sua variável estiver no começo, ela será obviamente considerada como o comando.

    
por 27.06.2016 / 07:30