Atribuindo comando à variável sem alias

Atribuindo comando à variável sem alias

Acabei de descobrir acidentalmente 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 bashbash --version GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

eu olhei paratroca de pilhaetldp abs, mas não descobrimos que podemos fazer assim. Então, esse é um novo recurso do bash ou algo que está sendo esquecido? Isso é consideradosubstituição de comando?

Responder1

No uso interativo, o shell lê as linhas de entrada do dispositivo terminal. Após uma linha ter sido inserida, éanalisadodividindo-se emfichas(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 consultar a fonte canônica de informações, como documentação do projeto ou especificações do setor, em vez de fontes de segunda mão, como o Advanced Bash-Scripting Guide, tutoriais on-line, livros – ou até mesmo 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 em fontes de segunda mão também podem estar desatualizadas.

Neste caso, oEspecificação POSIX para análise de comandos simplesafirma que

  1. As palavras que não sejam atribuições de variáveis ​​ou redirecionamentos deverão ser ampliadas. Se algum campo permanecer após sua expansão, o primeiro campo será considerado o nome do comando e os campos restantes serão os argumentos do comando.

OSeção do manual Bash sobre expansão de comando simplestambém afirma que

  1. As palavras que não são atribuições de variáveis ​​ou redirecionamentos são expandidas (consulte Expansões de Shell). Se sobrar alguma palavra após a expansão, a primeira palavra será considerada o nome do comando e as palavras restantes serão os argumentos.

Responder2

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

g=datearmazena a string datena 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 echocomando como o primeiro argumento. Se você executar "$g", isso colocará a string datena 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 das cotações, o“operador split+glob”é aplicado ao valor. Neste caso, isso significa que o valor de jjé dividido em duas palavras separadas por espaço. Assim, a palavra pingtermina na posição de comando e a palavra yahoo.comé o primeiro argumento.

Responder3

Este é um comportamento esperado e tem funcionado há muito tempo. É útil para criar comandos em scripts.

Digamos, por exemplo, que às vezes eu deveria aplicar descompactação em alguma entrada antes de enviá-la para um pipeline (e compactaçã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"

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

Isto é em vez dissoexpansão de parâmetros, ou seja, 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 seria executado gunzipem vez de gzip)

EDITAR:Sobre apelidos.

O bashmanual diz:

Para quase todos os propósitos, os aliases são substituídos pelas funções shell.

... e eu concordo.

Aliases são bons para coisas curtas como

alias ls="ls -F"

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

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

Se você tiver operações moderadamente complexas que executa regularmente, use funções shell para elas.

Tomando o exemplo da resposta aceita paraa questão U&L(que você vincula nos comentários abaixo):

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

Este alias obviamente funciona, mas usando

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

não funcionará se você tentar usar $my_Filecomo um comando na linha de comando (conforme explicado no tópico U&L).

Com uma função 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

Responder4

É simplesmente usar variáveis ​​shell, um conceito que existe e funciona assim há décadas (sem exageros).

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 início, obviamente ela será considerada como o comando.

informação relacionada