Como verificar se a string contém uma substring em traço ou cinza?

2

Aqui está o que estou tentando dizer:

#!/bin/sh
contains() {
    if $(echo $1 | grep -c $2) ; then
        echo "0" # contains
    else
        echo "1" # not contains
    fi
}

myString=$1
mySubsting=$2

contains $myString '$mySubsting'

Aqui está um exemplo de execução:

# sh ./myScript abcdef bc
./myTest: line 3: 0: command not found
1

EDITADO:

A pergunta original era: Como verificar se a string contém uma substring no Bourne Shell?

Aqui está o que estou tentando dizer:

  #!/bin/sh
  if echo $1 | grep -q $2
  then
    echo "0"
  else
    echo "1"
  fi

Aqui está um exemplo de execução:

$ sh ./myTest "$(systemctl status ntp)" "Active: active"
grep: active: No such file or directory
1

Como verificar corretamente se uma string contém outra?

    
por Alexandr 26.11.2016 / 22:03

2 respostas

5

O shell Bourne tinha uma construção para isso. É o mesmo que no moderno sh (que parece mais com o que você está usando, o shell Bourne não tinha suporte para $(...) ; se fosse o shell Bourne, você receberia um erro diferente):

case $1 in
  *"$2"*) printf '"%s" is in "%s"\n' "$2" "$1"
esac

Se você quisesse usar grep , seria:

if printf '%s\n' "$1" | grep -Fqe "$2"; then
  printf '"%s" is in "%s"\n' "$2" "$1"
fi

Ou

if grep -Fqe "$2" << EOF
$1
EOF
then
  printf '"%s" is in "%s"\n' "$2" "$1"
fi

Mas isso só funcionaria corretamente se $2 não contivesse nenhum caractere de nova linha.

Em qualquer caso, você precisa de aspas em torno da maioria dessas expansões de parâmetros. O único lugar onde não é necessário está em case $1 acima, mas mesmo assim case "$1" não prejudicaria.

Algumas notas no seu código:

  1. Você não pode usar echo para strings arbitrárias . Aqui, dependendo da implementação de echo , ele falharia nos valores de $1 como -n ou foo\bar .
  2. Deixar uma expansão de parâmetro sem aspas tem um significado muito especial em shells . Você não quer fazer isso. Tente, por exemplo, que grep -c $2 com um valor de $2 como * ou root /etc/passwd .
  3. grep sem -F é para correspondência de expressões regulares. Você precisa de -F para pesquisa de cadeia fixa (substring) (costumava ser com fgrep ), mas novamente se $2 contiver várias linhas, que diz grep -F para pesquisar qualquer do conteúdo dessas linhas na entrada ( grep -F $'a\nb' procuraria a ou b , não a $'a\nb' string).
  4. Em grep -c $2 , o conteúdo de $2 seria considerado uma opção se fosse iniciado com - . Você quer que grep -c -e "$2" ou grep -c -- "$2" evite isso.
  5. Você deseja usar o status de saída, não stdout, para relatar condições booleanas. Em scripts com exit ( exit 0 para true, exit 1 (ou qualquer número diferente de zero, mas evite valores maiores que 120) para false). Para funções, use return . Embora os scripts e funções retornem com o status do último comando de execução.
  6. $(cmd) expande para a saída de cmd (e passa por split + glob aqui por causa das aspas faltantes novamente) menos os caracteres de nova linha à direita. Portanto, se cmd produzir 0\n , $(cmd) se expandirá para 0 . Portanto, executar $(cmd) tenta executar o comando chamado 0 . Se você quiser converter a saída de cmd em um status de saída (para que possa ser usado como booleano), você precisará de (exit "$(cmd)") . Isso inicia um subshell que sai com a saída de cmd como seu código de saída).
  7. grep -c conta o número de ocorrências. Aqui você não precisa ter a contagem completa, você só precisa saber se ela é encontrada (se houver pelo menos uma partida). Para esse grep -q é mais eficiente, pois deixa de procurar depois de encontrar um. Para antigas implementações de grep que não suportam a opção (padrão) -q , você pode usar fgrep -le "$2" > /dev/null . Com -l , fgrep também pára na primeira correspondência, mas exibe o nome do arquivo (que descartamos aqui, redirecionando a saída para /dev/null ).
por 26.11.2016 / 22:21
1

o bash suporta isso nativamente;

$ string1="abcmoocow"
$ string2="moo"
$ if [[ $string1 == *$string2* ]]; then echo "Match"; else echo "No Match"; fi
Match
$ string1="abccrowcow"
$ if [[ $string1 == *$string2* ]]; then echo "Match"; else echo "No Match"; fi
No Match

também para corrigir o seu exemplo; mudar;

if $(echo $1 | grep -c $2) ; then

para se tornar:

if [ -n "$(echo $1 | grep -c $2)" ]; then

(verifica se o grep retorna algum dado)

observe também que também é possível trabalhar com o código de saída;

$ echo bob | grep "o" &>/dev/null; echo $?
0
$ echo bob | grep "z" &>/dev/null; echo $?
1
    
por 26.11.2016 / 23:34