Alguém pode explicar o que acontece nesta linha bash passo a passo? Sou novo aqui e estou tentando entender como esse código funciona, principalmente de echo
:
read char; echo -e "YES\nNO\n" | grep -i $char
Responder1
Os comandos na linha lêem uma string na variável char
, provavelmente de forma interativa do usuário.
O pipeline echo
+ grep
tenta determinar se a string inserida é afirmativa ou não. Ele faz isso combinando as palavras YES
e NO
com a string inserida (com a string inserida como padrão), sem distinção entre maiúsculas e minúsculas. Se o usuário inserir um caractere maiúsculo ou minúsculo ou uma substring presente na palavra YES
, o resultado será YES
; se eles inserissem um caractere maiúsculo ou minúsculo ou uma substring presente na string NO
, o resultado seria NO
. Inserir algo como maybe
resultaria em uma saída vazia.
A desvantagem dessa abordagem é que se o usuário inserir, por exemplo, .
, ambos YES
e NO
corresponderiam a grep
tratariam o ponto como uma expressão regular que corresponde a qualquer caractere. Como $char
não está entre aspas na chamada para grep
, também teria o potencial de causar um ataque de negação de serviço contra a máquina se o usuário inserir um padrão globbing de shell, como /*/*/*/*/../../../../*/*/*/*
input (exemplo retirado deImplicações de segurança de esquecer de citar uma variável em shells bash/POSIX). Você também pode causar confusão na saída do comando digitando, por exemplo -r -o -e . /
(irá gerar todos os caracteres de todos os arquivos não binários em uma linha por si só, precedida pelo nome do caminho do arquivo do qual faz parte).
O código que você mostra é "estranho e incomum", pois usa a entrada do usuário como algo que é essencialmentecódigo, ou seja, ele usa a entrada do usuário como umpadrãoe testa estáticadadoscontra esse padrão variável. Isso é o oposto do que normalmente se faz, que é pegar a entrada do usuário e testar esses dados variáveis em relação a um padrão estático.
É mais comum usar código semelhante ao seguinte:
read -p 'Yes/[N]o: ' yesno
if [[ $yesno == [Yy]* ]]; then
# code for affirmative
else
# code for non-affirmative
fi
O código acima lê uma string do usuário e testa se ela começa com um y
ou um Y
caractere. O primeiro ramo da if
instrução seria usado se isso acontecesse, mas else
caso contrário, o padrão seria pegar o ramo.
Obviamente, você também pode testar o Word inteiro YES
, ou [Yy][Ee][Ss]
uma correspondência que não diferencia maiúsculas de minúsculas, ou fazer um loop de entrada adequado com verificação:
while true; do
read -p 'Yes/No: ' yesno
if [ "$yesno" = Yes ] || [ "$yesno" = No ]; then
break
fi
echo 'Please enter "Yes" or "No"' >&2
done
# $yesno is either Yes or No here
(ou algo semelhante).
Observe como os dois códigos de exemplo acima usam a entrada do usuário exclusivamente como dados e nunca como padrão.
Reescrever seu comando original minimamente para algo um pouco idiomático (mas funcionalmente diferente e provavelmente não infalível) o transformaria em
read yesno; printf '%s\n' "${yesno^^}" | grep -i -w -E 'yes|no'
Isso retornaria letras maiúsculas YES
ou NO
se o usuário digitasse yes
ou no
. Isso é funcionalmente diferente, pois exige que o usuário digite algo mais do que apenas e
a yes
, por exemplo.
Responder2
Bem, vamos analisar cada comando por vez:
read char
Isso lerá a entrada padrão (normalmente o seu teclado, mas pode ser um arquivo indireto ou um fluxo canalizado; veja abaixo) e colocará os dados recebidos em uma variável chamada char
.
echo -e "YES\nNO\n"
echo
exibirá na saída padrão (normalmente o terminal) os parâmetros fornecidos. A -e
opção (frequentemente, mas nem sempre; echo
é meio problemática em relação à implementação consistente) permitirá que você e
escape de certos caracteres para fazer alguma formatação rudimentar. Nesse caso, está usando \n
, que é um escaped n
, que é uma abreviação de n
ewline.
grep -i $char
grep
é uma ferramenta para pesquisar a entrada fornecida para ver se há alguma correspondência para o padrão fornecido. A -i
opção informa que é uma i
pesquisa que não diferencia maiúsculas de minúsculas.
O |
entre os comandos echo
e grep
é um "tubo". Isso conecta a saída do primeiro comando à entrada do segundo, o que significa que grep
estaremos pesquisando neste corpus o padrão refletido no conteúdo da variável char
:
YES
NO
O resultado prático desta sequência de comandos é observar a entrada fornecida (assumida com base no nome da variável como sendo um único caractere, mas isso não é verificado). Se este caractere for Y
, E
, S
, y
, e
, ou s
, a saída será YES
. Se este caractere for N
, O
, n
ou o
, a saída será NO
. No entanto, se (por exemplo) a entrada for yo
ou ne
, nada será gerado.
Conforme observado anteriormente, a presunção de que a entrada é um caractere não é verificada. Este não é o único antipadrão na sequência de comandos de exemplo fornecida. Por exemplo, as variáveis não estão sendo citadas; e uma ferramenta de expressão regular ( grep
) está sendo usada sem que a entrada seja examinada para curingas regex.
Responder3
Um "caractere" (em vez de: string) é lido de /dev/stdin
. Significado: você digita.
Em seguida, duas linhas são enviadas para /dev/stdout
. Ou seja, seu console.
E através do pipe (o "|") isso é então digitado para a versão que não diferencia maiúsculas de minúsculas da sua entrada.
Isso significa que se você inserir "bar", ele simplesmente terminará sem qualquer saída aparente, mas se você inserir, digamos, "y", a linha "YES" será exibida, provavelmente até destacando o "Y"