web-dev-qa-db-ja.com

変数に改行が含まれているかどうかをテストします(POSIX)

一部のシェルがこの種のテストを受け入れることは知っています。

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

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

実行時:

$ bash ./script
yes no
  1. POSIX(ダッシュ)と同等の機能とは

  2. 以下は信頼できるテスト方法ですか?

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

変数にハード改行を入れて、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

改行を作成する別の方法は次のようなものです。

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

末尾の改行は置換によって削除されるため、明らかなコマンド置換は機能しません。

12
ilkkachu

はい、

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

(原則として、caseパターン内のすべての変数展開をパターンとして扱いたい場合を除いて引用します。ただし、ここでは$nlにはワイルドカードが含まれていないため、違いはありません) 。

または

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

すべてが機能し、POSIXに準拠している必要があります。 (sを削除すると、古いBourne Shellでも機能します。

$nl変数を設定する別の方法:

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

$'\n'は、POSIX標準の次のバージョンに含まれる予定です であることに注意してください。少なくともksh93zshbashmksh、busybox、FreeBSD shで既にサポートされています(2018年2月現在)。

あなたが持っているテストが十分であるかどうかに関しては、両方のケースのテストがあり、すべてのコードパスをテストすることになります。

現在、POSIX仕様で明確に指定されていないものがあります。*が、有効な文字を形成しないバイトシーケンスを含む文字列と一致するかどうか、またはシェル変数にそれらの文字列が含まれるかどうかです。

実際には、変数に文字のみを含めることができるyashとNULバイト(zsh以外の変数は変数に格納できない)を除いて、*$nl*は有効な文字を形成しないバイトのシーケンスが含まれている場合でも、$nlを含む文字列(UTF-8の$'\x80'など)。

たとえば、一部のfind実装はそれらの-name "*$nl*"との一致に失敗するため、新しいシェルをテストする場合、およびテキストであることが保証されていないもの(ファイル名など)を処理する場合は、そのためのテストケースを追加したいかもしれません。と同じように:

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

uTF-8ロケールで。

5