Como colocar uma pesquisa de strings com o comando grep em if statement?

11

Eu quero pesquisar várias strings em dois arquivos. Se uma string for encontrada em ambos os arquivos, faça alguma coisa. Se uma string for encontrada em apenas um arquivo, faça outra coisa.

Meus comandos são os próximos:

####This is for the affirmative sentence in both files
if grep -qw "$users" "$file1" && grep -qw "$users" "$file2"; then

####This is for the affirmative sentence in only one file, and negative for the other one
if grep -qw "$users" "$file1" ! grep -qw "$users" "$file2"; then

é correto o modo de negar e afirmar as afirmações? p.d. Estou usando o shell KSH.

Obrigado antecipadamente.

    
por Mareyes 23.08.2018 / 20:37

4 respostas

11

Tente isto:

if grep -wq -- "$user" "$file1" && grep -wq -- "$user" "$file2" ; then
   echo "string avail in both files"
elif grep -wq -- "$user" "$file1" "$file2"; then
   echo "string avail in only one file"
fi
  • grep pode procurar padrões em vários arquivos, portanto, não é necessário usar um operador OR / NOT.
por 23.08.2018 / 20:58
13

Outra opção:

grep -qw -- "$users" "$file1"; in_file1=$?
grep -qw -- "$users" "$file2"; in_file2=$?

case "${in_file1},${in_file2}" in
    0,0) echo found in both files ;;
    0,*) echo only in file1 ;;
    *,0) echo only in file2 ;;
      *) echo in neither file ;;
esac
    
por 23.08.2018 / 21:08
7
n=0

#Or if you have more files to check, you can put your while here. 
grep -qw -- "$users" "$file1" && ((n++))
grep -qw -- "$users" "$file2" && ((n++))

case $n in 
   1) 
       echo "Only one file with the string"
    ;;
   2)
       echo "The two files are with the string"
   ;;
   0)
       echo "No one file with the string"
   ;;
   *)
       echo "Strange..."
   ;;
esac 

Nota: ((n++)) é uma extensão ksh (também suportada por zsh e bash ). Na sintaxe% POSI sh , você precisaria de n=$((n + 1)) .

    
por 23.08.2018 / 20:56
2

Se os nomes dos seus arquivos não contiverem novas linhas, você poderá evitar várias invocações de grep fazendo com que o grep imprima os nomes dos arquivos correspondentes e conte os resultados.

 local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
 matches=( $(grep -lw "$users" "$file1" "$file2") )

O número de correspondências é "${#matches[@]}" .

Pode haver uma maneira de usar grep --null -lw aqui, mas não sei como analisar a saída . Bash var=( array elements ) não tem como usar um delimitador \n em vez de mapfile . Talvez bash -d string builtin pode fazer isso? Mas provavelmente não, porque você especifica o delimitador com count=$(grep -l | wc -l) .

Você pode usar grep , mas você tem dois processos externos, portanto, pode executar apenas grep nos dois arquivos separadamente. (A diferença entre wc vs. wc -l de sobrecarga de inicialização é pequena em comparação com o fork + exec + material de vinculador dinâmico para iniciar um processo separado).

Além disso, com $matches você não encontra o qual arquivo correspondente.

Com os resultados capturados em uma matriz, que já pode ser o que você quer, ou se houver exatamente 1 correspondência, você pode verificar se foi a primeira entrada ou não.

local IFS=$'\n'    # inside a function.  Otherwise use some other way to save/restore IFS
matches=( $(grep -lw "$users" "$file1" "$file2") )

# print the matching filenames
[[ -n $matches ]] && printf  'match in %s\n'  "${matches[@]}"

# figure out which input position the name came from, if there's exactly 1.
if [[ "${#matches[@]" -eq 1 ]]; then
    if [[ $matches == "$file1" ]];then
        echo "match in file1"
    else
        echo "match in file2"
    fi
fi

${matches[0]} é a abreviação de %code% , o primeiro elemento da matriz.

    
por 24.08.2018 / 21:05