
ファイルから読み取った行に、変数に格納されている単語を含む特定の開始と終了があるかどうかをテストしたいと思います。以下はいくつかのコードです。
入力ファイルは次のとおりです。
line one
#; line two
#; line three blah
line four
失敗する最小スクリプトは次のとおりです。
declare ENDOFLINE= "blah"
exec 3< "inputfile"
while read LINE <&3
do
if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE%$}") )) ]];
then
echo score!
else echo no score
fi
done
しかし、これを行うと:
if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "blah$") )) ]];
正しい行(=>#;3行目など)が正常に識別されました。つまり、行の先頭が "#;" で行の終わりが $ENDOFLINE 変数に含まれる文字列である場合、最初のテストを実行する複合テスト条件が必要です。
助けてくれてありがとう。
答え1
単純な間違いのように見えます。${ENDOFLINE%$}
最後からaを削除しましたが、必要なのは文字通り使用し、その後にaを付けて行の終わりをマークすることです。$
$ENDOFLINE
$ENDOFLINE
$
if [[ ("$LINE" =~ "^#;") && (( ("$LINE" =~ "${ENDOFLINE}$") )) ]];
これはzshでは機能しますが、kshまたはbashでは機能しません。 Bashでは正規表現を$
引用符で囲む必要があり(そうでない場合は文字通り解釈します)、kshは内部に二重括弧があることを好きではありません[[ … ]]
(算術命令として解釈します)。この単純なコード行は、3つのシェルすべてで動作します(変数の拡張を必要としない数少ない場所の1つ[[…]]
です)。"…"
if [[ $LINE =~ ^"#;" && $LINE =~ $ENDOFLINE$ ]];
$ENDOFLINE
と重複しない場合#;
(たとえば、ENDOFLINE
受け入れる;foo
が#;;foo
拒否する#;foo
)、これを単一のテストに減らすことができます。
if [[ $LINE =~ ^"#;".*$ENDOFLINE$ ]];
ここでは、正規表現の代わりにワイルドカードパターンを使用することもできます。
if [[ $LINE = "#;"*"$ENDOFLINE" ]];
この[[…]]
構成はすべてのシェルには存在せず、bash、ksh、zsh に固有のものです。他のシェル(Bourne、dash、POSIX)では、ワイルドカードの一致には次の設定を使用できますcase
。
case $LINE in
"#;"*"$ENDOFLINE") echo score;;
*) echo no score;;
esac
答え2
grepを使用してこれを行うこともできます。
end=blah
while read line; do
if grep -Eq "^#;.*$end$" <<< "$line"; then
echo score!
else
echo no score
fi
done
(これはbashにあります。他のシェルでは構文が多少異なる場合がありますが、原則は同じです。)