POSIX

POSIX

sed次のように(nullではないことが知られている)外部ユーティリティを呼び出すことで$myvarこれを行うことができます。

if [ "$(printf %s "$myvar" | sed -n '$=')" -eq 1 ]; then
  echo "Your variable has only one line, proceeding"
else
  echo "Error condition, variable must have only one line"
fi

bash組み込み関数のみを使用してこれを行う方法はありますか?

より良い点は、外部ユーティリティを呼び出さずにPOSIX指定の方法でこれを行う方法はありますか?


(この質問は好奇心とより良い作業方法を見つけることの1つです。上記のコードはする機能。もっときれいで速い方法があるかどうか疑問に思います。 )

答え1

POSIX方式:

NL='
'
case $myvar in
  *"$NL"*) echo more than one line ;;
        *) echo one line ;;
esac

これはPOSIX以前のBourne様シェルにも当てはまります。

答え2

いくつかのオプションがあります(bash まず、以下のPOSIX)。
各関数内のコードは、外部でも簡単に使用できます。

#!/bin/bash

nl=$'\n'

aregex   (){ [[ $a =~        $nl     ]]; }
apattern (){ [[ $a ==       *$nl*    ]]; }
acut     (){ [[ $a != "${a%%"$nl"*}" ]]; }
areplace (){ [[ $a != "${a//"$nl"/}" ]]; }
acase    (){ case $a in (*$nl*) true;; (*) false;; esac; }
aifs     ()( IFS="$nl"
             set -f; set -- x${a}x;
             (( $# > 1 ));
           )
aread    (){ IFS="$nl" read -rd '' -a b <<<"x${a}x";
             (( "${#b[@]}" > 1 )); }

すべての機能はオプションです。行が1つしかない場合、各関数は0の値で終了し、変数に複数の改行$a文字がある場合(multiple)$'\n'1の値で終了します。

関数を実行すると、必要な行が印刷されます。

out=''; "$function" && out="more than "
printf "%9s   = %sone line\n" "$1" "$out"

すべてのオプションを実行します。

a='ab'"$nl"'cd' ; alltests
a='ab  cd'      ; alltests

次の出力を提供します。

   aregex   = more than one line
 apattern   = more than one line
     acut   = more than one line
 areplace   = more than one line
    acase   = more than one line
     aifs   = more than one line
    aread   = more than one line

   aregex   = one line
 apattern   = one line
     acut   = one line
 areplace   = one line
    acase   = one line
     aifs   = one line
    aread   = one line  

POSIX

次のオプションは、いくつかの理由でPOSIXで失敗します。

  • =~areregex:POSIXには正規表現演算子はありません。
  • ==apattern:POSIXには演算子はありません。
  • areplace:パラメータ拡張にはオプションはありません${ / / }

そのうちの4つはPOSIXに安全に変換できます。

  • posixcut:おそらく最高の解決策でしょう。
  • posixcase:POSIXシェルのための一般的なソリューションです。
  • posixifs:setupを有効にするためにサブシェル内で実行されますset -f
  • -dposixread: 読み込みにはまたはがありませんが、変更されること-aがあります。

#!/bin/dash

nl='
'

posixcut (){ [ "${a}" != "${a%%"$nl"*}" ] ; }
posixcase(){ case $a in (*$nl*) true;; (*) false;; esac; }
posixifs ()( IFS="$nl";
             set -f; set -- x${a}x;
             [ "$#" -gt 1 ];
           )
posixread(){ local b=0;
             while IFS=$nl read -r _; do
                 b=$((b+1));
                 [ $b -gt 1 ] && break;
             done <<-_EOT_
x${a}x
_EOT_
             [ $b -gt 1 ];
           }

ノート:はい、local技術的にはPOSIXではありませんが、良いサポートを受ける
ローカルはb安全に取り外すことができます(グローバル$b使用量の確認)。

ボン・シュプリマシー(1977 Shell)。

1977年の元のBourneシェルのコードが必要な場合は、次のコードを使用してください。

posixcase() { case $a in *$nl*) true;; *) false;; esac; }
posixifs () ( IFS="$nl"
              set -f; set -- x${a}x;
              [ "$#" -gt 1 ];
            )
bourneread()( b=0                ### A helper function.
              while :; do
                  if IFS=$nl read c && [ $b -le 1 ]; then
                      b=`expr $b + 1`
                  else
                      echo "$b"
                      break
                  fi    
              done <<-_EOT_
x${a}x
_EOT_
             )
posixread   (){ [ `bourneread` -gt 1 ]; }

posixcut で使用される拡張は${a%% }Bourne では機能しません。 Bourneで動作するには、posixifを2つの部分に分割する必要があります。
読み取りオプションにはかなりの変更が必要ですが、正常に機能します。
その機能はposixreadで、bournereadは必須の補助機能です。

Bourneのすべてのコードは動作テストされています。ガボシェル

答え3

次のコードスニペットは機能しますbash(オプションの有無にかかわらず-posix)。

#!/bin/bash
#!/bin/bash -posix
version_1 () { [[ "$myvar" = *$'\n'* ]]; }
version_2 () {
  local newlines="${myvar//[^$'\n']/}"
  [[ "${#newlines}" -eq 1 ]]
}
for test in version_1 version_2; do
  if $test; then echo many lines; else echo one line; fi
done

答え4

次のように、Bashパラメータ拡張を使用することをお勧めします。

n="${myvar//[^\n]}"; if [ ${#n} -eq 1 ]; then
  echo "Your variable has only one line, proceeding"
else
  echo "Error condition, variable must have only one line"
fi

テストサンプル:

myvar="xxx"
myvar="xx\nxx"
myvar="xx\nx\nx"

関連情報