Ao executar history
na linha de comando, os resultados são assim:
$history aws s3 cp
16160 aws s3 cp s3://mybucket/air2008/10 .
16254 hists "aws s3 cp"
Para uma função hists
que se destina a ser um atalho para o acima:
type hists
hists is a function
hists ()
{
history 15000 | grep "$@"
}
Ao executá-lo, obtemos
09:40:44/csv $hists aws s3 cp
grep: s3: No such file or directory
grep: cp: No such file or directory
Se o executarmos com aspas, ele obterá o resultado correto. Mas então as citações são obrigatórias?
$hists "aws s3 cp"
“expande” parahistory 15000 | grep "aws s3 cp"
. Isso significa quegrep
recebe um único argumento.$hists aws s3 cp
expande parahistory 15000 | grep "aws" "s3" "cp"
.grep
recebe três argumentos.O primeiro argumento para
grep
é o padrão. Os outros argumentos são arquivos nos quaisgrep
encontrar o padrão. Não há arquivos chamadoss3
oucp
na pasta atual, portanto,grep
exibe mensagens de erro.As aspas podem alterar o significado do texto na linha de comando. Se você deseja que um argumento contenha espaços em branco, as aspas são uma maneira de fazer isso.
$hosts aws\ s3\ cp
faz a mesma coisa: adicionando uma barra invertida antes do espaço em branco, o shell sabe que não deve usar o significado usual, que é separar argumentos. Em vez disso, ele se tornará um espaço em branco literal.Também não há diferença de comportamento com
"$@"
. Ela existe precisamente para preservar os argumentos citados.A outra resposta é boa. Ele explica o que aconteceu:
Minha resposta permitirá que você robusteça e modifique a função para
hists aws s3 cp
que funcione.A primeira nota
grep "$@"
em seu código original permite que você injete opções paragrep
, assim:Você pode ou não querer ser capaz de fazer isso. Caso contrário, o trecho de código deve ser
grep -- "$@"
. Mas mesmo assim você poderá passar nomes de arquivos paragrep
. Espero que você nunca queira quegrep
a função opere em arquivos. Algum mecanismo para evitar isso seria útil.Se você quiser injetar opções, não há uma maneira trivial de impedir que você especifique arquivos como argumentos adicionais. A função deve passar vários argumentos para
grep
; ele não sabe por si só qual é uma opção, qual é um arquivo. Alguma lógica pode lidar com isso, mas vamos manter as coisas simples.Se você pode viver sem injetar opções em
grep
, pode garantir que a ferramenta receba apenas um argumento, o padrão. Você pode usargrep -- "$1"
, mas neste casoserá equivalente a
hists aws
, argumentos adicionais não importarão. Isso não é exatamente o que você deseja, mas impedirágrep
a análises3
ecp
/ou lançamento de erros sobre eles.Ou você pode usar
grep -- "$*"
. Isto é o que o POSIX diz sobre"$*"
:O interior das aspas é "um contexto onde a divisão de campo não será realizada" e o padrão
IFS
começa com <espaço>. Isso significa que se você usargrep -- "$*"
, o comandoirá desencadear
grep -- "aws s3 cp"
, que é o que você queria em primeiro lugar. Observe que você obterá o mesmo resultado comapesar dos vários espaços. O ponto é
hists
que não vê esses espaços. Ele vêaws
,s3
ecp
como argumentos separados, então o mecanismo de"$*"
concatena as três strings usando espaços simples.Por outro lado, estes comandos:
funcionará exatamente como você esperaria, independentemente de você usar
grep -- "$*"
ougrep -- "$@"
ougrep -- "$1"
. As três variantes se comportam de maneira diferente quando há mais argumentos parahists
; ou menos (tentehists
sem nenhum argumento).Assim
grep -- "$*"
, você pode tornar as aspas opcionais em alguns casos. Essa variante também impedirágrep
a análise de arquivos, independentemente do que você digitar.