grep comando não está funcionando na declaração condicional

4

Eu tenho um script que deve passar por todos os nomes de arquivos e imprimi-los apenas aqueles que contêm uma certa letra (digamos que seja 'o').

O que eu fiz:

command='ls -l'
for file in $command
do
  if $file | grep 'o' ;
  then
  echo "$file"
  fi
done

Isso não funciona, ele diz "comando não encontrado" na linha:

if $file | grep 'o' ;

Eu procurei várias outras respostas aqui e elas estão fazendo a mesma coisa que eu, ou seja, sem parênteses para a declaração if, a mesma sintaxe, etc.

O que eu estou negligenciando?

    
por Kocka Mijalkova 25.05.2015 / 01:37

4 respostas

10

$file | grep -o executa o comando especificado pelo valor de file e pipes sua saída para% código%. Mas isso claramente não é o que você queria.

Se você deseja listar arquivos que contenham grep

Você quis dizer que o valor de o é um arquivo de entrada para file , não um comando para executar. Então você precisa de um redirecionamento de entrada , não um canal.

if grep 'o' <"$file"

grep lê a entrada padrão se não receber um nome de arquivo em sua linha de comando. Você também pode passar um nome de arquivo na linha de comando; isso faz a mesma coisa.

if grep 'o' -- "$file"

Por que as aspas duplas e por que o grep no segundo método, consulte Por que meu script de shell sufoca em espaços em branco ou outros caracteres especiais?

Para suprimir a saída de -- , use a opção grep ou redirecione a saída para -q .

if grep -q 'o' <"$file"

ou

if grep 'o' <"$file" >/dev/null

Outro problema com o seu script é que /dev/null define a variável command='ls -l' para a saída do comando command , que não é uma lista de nomes de arquivos. Se você se lembra Por que meu script de shell sufocar no espaço em branco ou outros caracteres especiais? , você vai se lembrar que é impossível armazenar uma lista de nomes de arquivos em uma variável string : todos os nomes de arquivos são misturados. Aqui, é ainda pior: há lixo como permissões, datas, etc. A maneira de obter uma lista de nomes de arquivos em um script de shell é usar um padrão curinga .

for file in *
do
  if grep -q 'o' <"$file"
  then
    echo "$file"
  fi
done

Tudo isso é equivalente a

grep -l 'o' -- *

Se você deseja listar arquivos cujo nome contenha ls -l

Este recurso está embutido no shell, com padrões de curingas . O padrão o corresponde a nomes de arquivos que contêm *o* , portanto, para listá-los, você precisa apenas

ls -l -- *o*

O o é necessário no caso de um dos nomes de arquivos começar com -- , caso contrário, - poderá interpretar o nome do arquivo como uma opção.

Se este for um exercício de aprendizado sobre o uso de ls e você quiser passar o nome do arquivo como entrada para grep , será necessário usar o comando grep .

echo "$file" | grep 'o'

O comando echo pode manejar alguns nomes de arquivos. Por segurança, use echo . Para saber mais sobre isso e sobre o uso de aspas duplas, consulte Por que meu script de shell sufoca em espaços em branco ou outros caracteres especiais?

printf '%s\n' "$file" | grep 'o'

Como acima, não analise a saída de printf .

for file in *
do
  if printf '%s\n' "$file" | grep -q 'o'
  then
    printf '%s\n'
  fi
done

Se os nomes dos seus arquivos não contiverem novas linhas, você poderá reduzi-lo para.

for file in *
do
  printf '%s\n' "$file" | grep 'o'
done

Mais uma vez, o loop é inútil aqui e você pode usar apenas

printf '%s\n' *o*

para imprimir os nomes dos arquivos correspondentes em linhas separadas. O uso de ls só seria justificado se você precisasse de uma expressão regular de que os padrões de caractere curinga do seu shell não são poderosos o suficiente para serem expressos.

    
por 25.05.2015 / 01:51
5

Você está tentando executar $file . Em vez disso, você deve ecoar:

# ...
if echo "$file" | grep 'o' ;
# ...

Observe que o grep já imprime o nome do arquivo, por isso você deve silenciá-lo (por exemplo, grep -q 'o' ou grep 'o' >/dev/null ).

Você também está passando -l para ls , o que você não deseja deseja fazer. ls -l imprime o nome e os atributos do arquivo e você estará correspondendo a eles.

Além disso, você pode querer usar aspas se espera que funcione com qualquer arquivo, mas essa não é a origem do problema.

P.S .: Como outros já apontaram, você não deve usar ls para começar.

    
por 25.05.2015 / 01:46
1

Você não deve confiar na saída ls . ls foi criado para mostrar resultados amigáveis para humanos e não para ser usado em scripts. Veja o exemplo a seguir;

for f in ./*
  do 
   if [[ $f = *o* ]]; then 
    printf '%s\n' "$f"
   fi
 done
    
por 25.05.2015 / 01:50
-1

Primeiro, não é assim que você canaliza algo para o grep. Além disso, é geralmente considerado melhor forma de separar os comandos da condicional e apenas verificar os códigos de retorno.

Algo como o seguinte funciona perfeitamente:

command='ls -l'
for file in "$command"
do
  echo "$file" | grep 'o'
  if [ $? -eq 0 ]; then
    echo "$file"
  fi
done
    
por 25.05.2015 / 18:10