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
。 -d
posixread: 読み込みにはまたはがありませんが、変更されること-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"