Testen Sie, ob die Variable Zeilenumbruch enthält (POSIX)

8

Ich weiß, dass einige Muscheln diese Art von Test akzeptieren:

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

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

bei der Ausführung:

$ bash ./script
yes no
  1. Was ist das POSIX (Dash) Arbeitsäquivalent

  2. Ist das Folgende eine zuverlässige Methode zum Testen?

    nl='
    '
    
    t() {  case "$var" in
               *$nl* ) res=yes ;;
               * ) res=no ;;
           esac
           printf '%s ' "$res"
         }
    
    var='ab
    cd'
    t
    var='abcd'
    t
    echo
Isaac
quelle

Antworten:

12

Sie können eine feste neue Zeile in eine Variable einfügen und das Muster mit übereinstimmen 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

Der alternative Weg, um die Newline zu erstellen, ist ungefähr so:

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

Die offensichtliche Befehlssubstitution funktioniert nicht, da nachfolgende Zeilenumbrüche durch die Substitution entfernt werden.

ilkkachu
quelle
5

Ja,

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

(Grundsätzlich zitiere ich gerne alle variablen Erweiterungen innerhalb des caseMusters, es sei denn, ich möchte, dass sie als Muster behandelt werden, obwohl dies hier keinen Unterschied macht, da $nles keine Platzhalter enthält.)

oder

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

Sollten alle funktionieren und POSIX-konform sein, und was würde ich dafür verwenden. Wenn Sie das (s entfernen , würde es sogar in der alten Bourne-Shell funktionieren.

Für eine andere Möglichkeit, die $nlVariable festzulegen:

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

Beachten Sie, dass $'\n'die Aufnahme in die nächste Version des POSIX-Standards geplant ist . Es ist bereits unterstützt ksh93, zsh, bash, mksh, Busybox und FreeBSD shmindestens (Stand : Februar 2018).

Ob der Test, den Sie haben, ausreicht, Sie haben einen Test für beide Fälle, also würden Sie alle Codepfade testen.

Derzeit ist in der POSIX-Spezifikation etwas nicht eindeutig angegeben: ob *Übereinstimmungen mit einer Zeichenfolge, die Byte-Sequenzen enthält, die keine gültigen Zeichen bilden, oder ob Shell-Variablen diese Zeichenfolgen enthalten können.

In der Praxis sollten abgesehen davon, yashderen Variablen nur Zeichen enthalten können und abgesehen von den NUL-Bytes (die keine Shell, sondern zshin ihren Variablen speichern kann), *$nl*alle Zeichenfolgen übereinstimmen, die enthalten, $nlauch wenn sie Folgen von Bytes enthalten, die keine gültige Form haben Zeichen (wie $'\x80'in UTF-8).

Einige findImplementierungen stimmen beispielsweise nicht mit -name "*$nl*"ihnen überein. Wenn Sie also eine neue Shell testen und sich mit Dingen befassen möchten, bei denen nicht garantiert ist, dass es sich um Text handelt (z. B. Dateinamen), möchten Sie möglicherweise einen Testfall hinzufügen. Wie bei:

test=$(printf '\200\n\200')

in einem UTF-8-Gebietsschema.

Stéphane Chazelas
quelle