Uji apakah variabel berisi baris baru (POSIX)

8

Saya tahu bahwa beberapa cangkang menerima tes semacam ini:

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

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

pada eksekusi:

$ bash ./script
yes no
  1. Apakah yang dimaksud dengan POSIX (tanda hubung) yang berfungsi

  2. Apakah mengikuti cara yang dapat diandalkan untuk menguji?

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

Jawaban:

12

Anda bisa meletakkan garis keras di dalam variabel, dan mencocokkan pola 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

Cara alternatif untuk membuat baris baru adalah sesuatu seperti ini:

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

Substitusi perintah yang jelas tidak berfungsi karena trailing baris baru dihilangkan oleh substitusi.

ilkkachu
sumber
5

Iya,

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

(pada prinsipnya, saya suka mengutip semua ekspansi variabel di dalam casepola kecuali saya ingin mereka diperlakukan sebagai pola, meskipun di sini tidak ada bedanya karena $nltidak mengandung wildcard).

atau

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

Haruskah semua bekerja dan sesuai dengan POSIX, dan apa yang akan saya gunakan untuk itu. Jika Anda menghapus (s, itu bahkan akan bekerja di shell Bourne yang lama.

Untuk cara lain mengatur $nlvariabel:

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

Catatan yang $'\n'direncanakan untuk dimasukkan dalam versi standar POSIX berikutnya . Ini sudah didukung oleh ksh93, zsh, bash, mksh, busybox dan FreeBSD shsetidaknya (per Februari 2018).

Adapun apakah tes yang Anda miliki sudah cukup, Anda sudah mendapatkan tes untuk kedua kasus sehingga akan menguji semua jalur kode.

Saat ini ada sesuatu yang tidak ditentukan dengan jelas dalam spesifikasi POSIX: apakah *cocok pada string yang berisi urutan byte yang tidak membentuk karakter yang valid atau apakah variabel shell mungkin berisi string tersebut.

Dalam praktiknya, selain dari yashvariabel yang hanya dapat berisi karakter, dan selain dari byte NUL (yang tidak ada shell tetapi zshdapat disimpan dalam variabel mereka), *$nl*harus cocok dengan string apa pun yang berisi $nlbahkan jika mereka berisi urutan byte yang tidak membentuk valid karakter (seperti $'\x80'dalam UTF-8).

Beberapa findimplementasi misalnya akan gagal cocok dengan -name "*$nl*"mereka, jadi jika menguji shell baru, dan jika Anda bermaksud untuk berurusan dengan hal-hal yang tidak dijamin menjadi teks (seperti nama file), Anda mungkin ingin menambahkan test case untuk itu. Suka dengan:

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

di lokal UTF-8.

Stéphane Chazelas
sumber