Qual a diferença entre $ _ e! $? [duplicado]

3

Eu sempre usei !$ para se referir ao último argumento do comando anterior.

por exemplo,

~/dir » mkdir birthday
~/dir » cd !$
~/dir » cd birthday

No entanto, comecei a ver tutoriais usando $_ no lugar de !$

Eu testei os dois e a única diferença que notei é sutil, mas parece que $_ irá avaliar e executar o comando enquanto !$ permitirá que você verifique a saída antes de pressionar Enter , mas esta é a única diferença entre $_ e !$ ?

Atualização: sinalizado como duplicado? Esta questão pode ser respondida pela resposta aceita para a questão sugerida, mas apenas porque a resposta é mais detalhada do que a pergunta requerida.

Procurando por O que _ $ significa? produz a duplicata sugerida, mas eu já sabia antes de perguntar o que !$ fez, e não há nada que sugira que essa pergunta também possa responder outras perguntas.

    
por Luke 04.11.2017 / 02:45

1 resposta

6

man bash , procure a seção Parâmetros especiais . Por _ você encontrará:

expands to the last argument to the previous command, after expansion.

Assim, em um contexto de linha de comando, a diferença é a expansão. Por exemplo, se eu tiver uma variável FOO definida como 'bar' e executar echo $FOO , então $_ na próxima linha resultará em bar sendo enviado no próximo comando, enquanto !$ resultará em $FOO .

Esse comportamento pode não ser óbvio por padrão, mas com shopt -s histverify é um pouco mais evidente. (Com histverify habilitado, o Bash não enviará a expansão do histórico imediatamente após Enter , primeiro exibirá o comando, pós-expansão, e aguardará um segundo Enter ). Então, veríamos algo assim depois de FOO=bar :

$ echo $FOO
bar
$ ls !$ $_
# We hit Enter and then see
$ ls $FOO $_ 

$_ não é expandido até que o comando seja submetido durante a expansão do parâmetro (juntamente com $FOO ). É uma distinção sutil, mas lá vai você.

Provavelmente, a distinção mais interessante / útil é que $_ é uma variável . Portanto, por exemplo, se o último parâmetro for /some/file/path.txt , você poderá obter o comprimento ${#_} -> 19 , extrair apenas o nome do arquivo ${_##*/} -> path.txt , alterar a raiz ${_//some/other} -> /other/file/path.txt e assim por diante. Não é possível fazer tudo isso com !$ .

Observe que $_ tem significados diferentes em outros contextos:

At shell startup, set to the absolute pathname used to invoke the shell or shell script being executed as passed in the environment or argument list.

... e ...

Also set to the full pathname used to invoke each command executed and placed in the environment exported to that command.

... e ...

When checking mail, this parameter holds the name of the mail file currently being checked.

ATUALIZAÇÃO: Embora seja mais preciso, minha resposta carece de algumas informações importantes e talvez até enganosas sobre como / quando $_ realmente obtém um valor. Essa primeira citação destina-se a ler assim:

expands to the last argument to the previous command as it was received by that command, i.e. after going through Shell Expansion

A melhor maneira de ilustrar é com alguns exemplos:

$ echo "$(date +%s)" # %s is seconds since epoch
1536984661
$ echo $_  "$(date +%s)" # don't hit enter until a few seconds pass
1536984661 1536984665

Portanto, $_ obtém os segundos reais desde a época calculados no momento em que o primeiro echo foi executado não perto da invocação 1536984665 do segundo date .

Outro:

$ foo='a b c'
$ echo "$foo"
a b c
$ echo "$_"
a b c
$ #---------
$ echo $foo
a b c
$ echo "$_"
c

No segundo caso, não citamos $foo . Antes de ser passado para echo , passou pela expansão de variável / parâmetro seguida de divisão de palavras. A falta de aspas resultou em "a", "b" e "c" sendo passados como três parâmetros separados e $_ obteve o último, ou seja, "c".

    
por 04.11.2017 / 03:21