「test」の2つの表現をXORする方法は?

「test」の2つの表現をXORする方法は?

ディレクトリ(と呼ばれる)に2つのファイル(と呼ばれるdir)のうちの1つが含まれていますが、ファイルが1つもなく両方が含まれていないことを確認する必要があります。fileafileb

理想的な解決策は、述語間でXOR演算を使用することです。

if [ -f dir/filea ] ^ [ -f dir/fileb]
then
    echo Structure ok
    # do stuff
fi

ただし、シェルはこれを^XOR演算子としてサポートしておらず、[オプションなしでコマンドと一緒に-Xまたは--xor同様の負の-a同等-o性を使用することも機能しません。

if ! [ -f dir/filea -eq -f dir/fileb ]
# or
if ! [ -f dir/filea = -f dir/fileb ]

このような本格的なAND / OR式を使用せずにこれを達成する方法はありますか?

if { [ -f dir/filea ] || [ -f dir/fileb ]; } && ! { [ -f dir/filea ] && [ -f dir/fileb ]; }

最後の表現は読みにくくなり、確かに私の実際のパスはdir/fileX

編集する:POSIX準拠のバージョンを目指していますが、他のシェルに関連する拡張にはオープンです(主に好奇心が強いため、sh他のプロジェクトでまたはbash使用しているためksh93便利です)。

ベストアンサー1

test ...または、コマンドの終了コード[ ... ]はテスト結果です。変数を使用して個々のテスト結果を保存し、後で比較することができます。

[ -f dir/filea ]
testA=$?
[ -f dir/fileb ]
testB=$?
if [ "$testA" -ne "$testB" ]
then
   echo "exactly one file"
else
   echo "both files or none"
fi

これにより、[両方のテストでゼロ以外の終了コードが生成される可能性があります。
仕様によるとhttps://pubs.opengroup.org/onlinepubs/007904875/utilities/test.html、終了コードは>1「エラーが発生しました」を意味します。[エラーが報告されたときに何が起こるかを定義する必要があります。

これを防ぐには、次のような条件付き変数割り当てを使用できます。コサロナンダの答え...

testA=0
testB=0
[ -f dir/filea ] || testA=1
[ -f dir/fileb ] || testB=1
if [ "$testA" -ne "$testB" ]
then
   echo "exactly one file"
else
   echo "both files or none"
fi

...またはコメントに記載されているように、否定を使用して値が0orであることを確認してください1
(「2.9.2パイプライン」 - 「終了ステータス」を参照)https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_02)

! [ -f dir/filea ]
testA=$?
! [ -f dir/fileb ]
testB=$?
if [ "$testA" -ne "$testB" ]
then
   echo "exactly one file"
else
   echo "both files or none"
fi

どちらのバリエーションも「ファイルが存在しません」と同じ方法でエラーを処理します。

おすすめ記事