Teste se a variável contém nova linha (POSIX)

7

Eu sei que alguns shells aceitam esse tipo de teste:

t() { [[ $var == *$'\n'* ]] && res=yes || res=no
      printf '%s ' "$res";
    }

var='ab
cd'
t
var='abcd'
t
echo

na execução:

$ bash ./script
yes no
  1. Qual é o equivalente de trabalho POSIX (traço)

  2. O seguinte é um modo confiável de testar?

    nl='
    '
    
    t() {  case "$var" in
               *$nl* ) res=yes ;;
               * ) res=no ;;
           esac
           printf '%s ' "$res"
         }
    
    var='ab
    cd'
    t
    var='abcd'
    t
    echo
    
por Isaac 04.02.2018 / 23:26

2 respostas

5

Sim,

nl='
'
case $var in
  (*"$nl"*) echo yes;;
  (*)       echo no;;
esac

(por princípio, eu gostaria de citar todas as expansões de variáveis dentro de case padrão, a menos que eu queira que elas sejam tratadas como um padrão, embora aqui não faça diferença, pois $nl não contém curingas). / p>

ou

case $var in
  (*'
'*) echo yes;;
  (*) echo no;;
esac

Todos devem funcionar e são compatíveis com POSIX, e o que eu usaria para isso. Se você remover o ( s, ele funcionaria no shell Bourne antigo.

Para outra maneira de definir a variável $nl :

eval "$(printf 'nl="\n"')"

Note que $'\n' está planejado para inclusão na próxima versão do padrão POSIX . Ele já é suportado pelo ksh93 , zsh , bash , mksh , busybox e FreeBSD sh pelo menos (em fevereiro de 2018).

Quanto a saber se o teste que você tem é suficiente, você tem um teste para ambos os casos, então testaria todos os caminhos de código.

Atualmente, há algo que não é especificado claramente na especificação POSIX: se * corresponde a uma string que contém sequências de bytes que não formam caracteres válidos ou se as variáveis do shell podem conter essas sequências.

Na prática, além de yash , cujas variáveis podem conter apenas caracteres, e além dos bytes NUL (que nenhum shell, mas zsh pode armazenar em suas variáveis), *$nl* deve corresponder em qualquer sequência que contenha $nl , mesmo que contenham sequências de bytes que não formam caracteres válidos (como $'\x80' em UTF-8).

Algumas implementações de find , por exemplo, não seriam compatíveis com -name "*$nl*" , portanto, se você testar um novo shell e tiver a intenção de lidar com itens que não têm garantia de texto (como nomes de arquivos), deseja adicionar um caso de teste para ele. Como com:

test=$(printf '0\n0')

em uma localidade UTF-8.

    
por 05.02.2018 / 12:56
12

Você pode colocar uma nova linha em uma variável e uma correspondência de padrão com case .

$ cat nl.sh
#!/bin/sh
nl='
'
case "$1" in
    *$nl*)  echo has newline ;;
    *)      echo no newline  ;;
esac

$ dash nl.sh $'foo\nbar'
has newline
$ dash nl.sh $'foobar'
no newline

A maneira alternativa de criar a nova linha é algo assim:

nl=$(printf "\nx"); nl=${nl%x}

A substituição óbvia do comando não funciona porque as novas linhas são removidas pela substituição.

    
por 04.02.2018 / 23:36