Como comparar 2 strings no shell script do UNIX? [duplicado]

4

Eu tenho uma variável que armazena uma string, a saída de um comando sed. Eu quero executar um conjunto de comandos somente se este valor de seqüência de caracteres coincide com uma das outras duas seqüências de caracteres.

Eu usei o código abaixo.

#! /bin/ksh
request=”Request”
fault=”Fault”
while read lines; do
    category='echo $lines|sed -n -e 's/.*Summary: Value//p'| awk '{print $1}''
    if [ ! -z "$category" ]
    then
        if($category = $request)
        then
            echo $category
        fi
     fi
done<content.txt

Mas isso está me dando um erro:

sample.sh: Request: not found

A categoria da variável terá o valor Request ou o valor Order

Alguém pode apontar o erro ou uma solução para isso?

Se inner if for eliminado e echo $category imprimirá o valor exato da string.

    
por Devjith 30.08.2018 / 11:09

7 respostas

12

Resposta simples para fazer isso, você pode usar esta sintaxe:

if [ "$category" = "$request" ]

O espaçamento é importante. Nota lateral, você deve usar a maneira recente de fazer o comando subsitition e substituir (veja artigo 1 e artigo do posix ):

category='echo $lines|sed -n -e 's/.*Summary: value//p'| awk '{print $1}''

por este

category=$(echo $lines|sed -n -e 's/.*Summary: value//p'| awk '{print $1}')
    
por 30.08.2018 / 11:17
10

Outros já apontaram o erro de sintaxe na sua declaração if .

Também gostaria de comentar sobre o fato de que você parece usar aspas duplas, , em vez das comuns, " . Você também não precisa armazenar a saída de sed em uma variável separada por meio dessa substituição de comando. Em vez disso, leia diretamente a saída awk :

#!/bin/ksh

sed -n 's/.*Summary: Value//p' <content.txt | awk '{ print $1 }' |
while IFS= read -r category; do
    case $category in
        Request|Fault)
            printf '%s\n' "$category"
            ;;
        Breakfast)
            echo 'Yum'
            ;;
        *)
            printf 'Unknown category: %s\n' "$category"
    esac
done

Ou, se você estiver mais à vontade com if -statements,

#!/bin/ksh

sed -n 's/.*Summary: Value//p' <content.txt | awk '{ print $1 }' |
while IFS= read -r category; do
    if   [ "$category" = 'Request' ] || [ "$category" = 'Fault' ]; then
        printf '%s\n' "$category"
    elif [ "$category" = 'Breakfast' ]; then
        echo 'Yum'
    else
        printf 'Unknown category: %s\n' "$category"
    fi
done

Note que não há necessidade de testar se a string está vazia. Uma string vazia pode ser comparada a outra string sem problemas, contanto que você cite sempre a expansão da variável .

Ou, se o seu script não estiver fazendo nada além disso:

#!/bin/ksh

sed -n 's/.*Summary: Value//p' <content.txt | awk '
    $1 == "Request" || $1 == "Fault" { print $1;    next }
    $1 == "Breakfast"                { print "Yum"; next }
                                     { printf("Unknown category: %s\n", $1) }

Relacionados:

por 30.08.2018 / 11:27
5

Devemos usar [ em vez de ( se a condição

Tente:

 if [ "$category" = "$request" ]
  • () usado para executar o comando e verificar o código de saída.
  • [] usado para verificar a expressão.

E eu espero que você tenha copiado o script do MS-word, já que ele possui um caractere não-unix

request=”Request”
fault=”Fault”

Edite isso como

request="Request"
fault="Fault"
    
por 30.08.2018 / 11:18
3

Quero apenas comentar a parte mais importante:

if($category = $request)

Um shell if funciona de outra forma, executando um comando e usando seu código de retorno.

Um exemplo é:

if /usr/bin/somecommand; then
    echo "somecommand exited with exit code 0 (success)"
fi

para comparar duas strings, você usaria

if /bin/test a = b; then
    echo "a=b"
fi

Note que test pode ser embutido em seu shell, mas você geralmente também o possui como binário.

A próxima coisa é que você geralmente tem um link simbólico de /bin/[ para /bin/test . Isso significa que você pode fazer:

if [ a = b ]; then
    echo "a=b"
fi

em que [ a = b ] é igual a test a = b e o ] está lá apenas para uma sintaxe mais agradável.
Esta é a razão, porque if [a=b] não funciona, pois a sintaxe acima significa [ "a" "b" "]" , onde [ é um nome de programa. Sem o espaço, o shell está procurando [a=b] .

Sua sintaxe usando (a = b) usa uma subshell para executar o comando dentro, resultando em um comando a = b , onde a é considerado um nome de programa.

Outra possível armadilha do seu código é que as variáveis podem estar vazias. Dê uma olhada neste código:

b=something
if [ $a = $b ]; then
    echo $a = $b
fi

Isso causará um erro, porque é equivalente a test = something (executando test "=" "something" ). O echo abaixo tem um problema semelhante, mas para o eco isso não importa muito. A maneira de corrigir isso é usar aspas apropriadas:

b=something
if [ "$a" = "$b" ]; then
    echo "$a = $b"
fi

Resultando na linha de comando do teste: test "" "=" "something" , que é um comando correto. Eu consertei problemas potenciais na linha de eco colocando a string inteira entre aspas, o que os torna um único parâmetro para o comando echo (ou interno).

    
por 30.08.2018 / 14:38
1

Além de todas as outras respostas,

  1. awk é um programa muito poderoso. É raro que você precise combiná-lo com outro comando de formatação de texto. Por exemplo,
    sed -n -e 's/.*Summary: Value//p' | awk '{print $1}'
    pode ser convertido em
    awk '{ if (sub(/.*Summary: Value/, "")) print $1 }'
  2. Você deve sempre citar as variáveis do shell (por exemplo, "$lines" , "$category" e "$request" ) a menos que você tenha uma boa razão para não fazer isso, e você está certo de que sabe o que está fazendo.
  3. Como Kusalananda apontou , usar um loop de shell para processar um texto é considerado uma prática ruim . Como eu disse acima, awk é um programa muito poderoso. Eu presumo que você entenda que seu script lê seu arquivo uma linha por vez, e invoca awk (e sed !) uma vez para cada linha. Sem explicitamente apontar, Kusalananda deu-lhe soluções de exemplo que executam awk (e sed ) uma vez para o arquivo inteiro; o último coloca toda a lógica no script awk , em vez do código shell. Essa é provavelmente a melhor abordagem se tudo o que você está fazendo é imprimir strings, como sua pergunta indica. Mas, mesmo se você precisar executar outros comandos com base na entrada, você pode fazer isso usando a função system() em awk . A complexidade da sua tarefa será um fator para decidir qual é a melhor abordagem.
por 31.08.2018 / 01:45
0

Aqui está uma maneira um pouco mais criativa. Se eu entendi corretamente, você só quer agir se $ category for Order or Request (ou qualquer outra coisa) e agir da mesma forma.

if (( $(echo -e "Request\nOrder\n$category" | sort -u | wc -l) == 2)); then
  echo $category
fi

Está apenas usando o fato de que, se a palavra desejada for usada, a ordenação removerá uma linha devido a tornar a lista única (-u). Caso contrário, a lista permanecerá em três linhas.

    
por 30.08.2018 / 21:23
0

Isso deve funcionar, pois há () em vez de [] em sua declaração if($category = $request)

#!/bin/ksh
request="Request"
fault="Fault"
while read lines; do
    category=$(echo $lines|sed -n -e 's/.*Summary: Value//p'| awk '{print $1}')
    if [ ! -z "$category" ]
    then
        if [[ $category = $request ]]
        then
            echo $category
        fi
     fi
    done<input.txt

    #contents of input.txt
    Summary: Value Request
    Summary: Value Order
    
por 31.08.2018 / 09:22