シェルグローブのXOR

シェルグローブのXOR

最近、私のホスティングプロバイダがpublic_html私が知らない間に私のディレクトリ名を変更したので、この変数宣言はもはや有効ではありません。wwwweb_application_root="${HOME}/public_html"

public_html"そのホスティング環境では必ずしも必要ではありませんが、同様の将来の状況のた​​めにBashにXORベースの変数を生成するように指示したいと思いますwww

可能であればどのように可能ですか?

答え1

私の考えでは、あなたはもっとうまくできないと思います。

web_application_root="${HOME}/public_html"
if [ ! -d "$web_application_root" ] ; then
   web_application_root="${HOME}/www"
fi

さまざまな形で。例えば

for loc in "${HOME}/public_html" "${HOME}/www" ; do
   web_application_root=$loc
   [ -d "$loc" ] && break
done

本質的に存在する最初のディレクトリを見つけて使用します。

答え2

ここでスレッドの質問に答えようとしています。

*.txtワイルドカードは、一致するファイルパスのリストなど、ワイルドカードパターンを拡張したものです。

files=(~/*.txt)

~名前が配列の個々の要素で終わる隠しファイルのリストを割り当てます(globがファイルと一致しない場合の動作はシェルによって異なります)。.txt$files

XOR(A, B)Aor が true の場合は True ですBが、どちらも True ではないため、次のようになります。AND(OR(A, B), NOT(AND(A, B)))

私はXORglob/ワイルドカード演算子を持つシェルを知りませんが、いくつかのシェルには1つのものがORありますNOT。 )。ANDAND(X, Y)NOT(OR(NOT(X), NOT(Y)))XORAND-NOTAND AND-NOT(X, NOT(Y))

この式を組み合わせると、次のような結果が得られます。

XOR(A, B) == NOT(OR(NOT(OR(A, B)), NOT(NOT(NOT(OR(NOT(A), NOT(B)))))))

これは次のように単純化できます(二重の不正除去)。

XOR(A, B) == NOT(OR(NOT(OR(A, B)), NOT(OR(NOT(A), NOT(B)))))

kshまたはbash -o extglob(または)グローバル変数に変換すると、zsh -o kshglob次のようになります。

!(!(A|B)|!(!(A)|!(B)))

またはzsh -o extendedglobグローブを使用してください:

^(^(A|B)|^(^A|^B))

または以下を使用してくださいAND-NOT

XOR(A, B) == AND-NOT(OR(A, B), NOT(NOT(AND-NOT(A, NOT(B)))))

次のように単純化できます。

XOR(A, B) == AND-NOT(OR(A, B), AND-NOT(A, NOT(B)))

zsh -o extendedglobglobに変換されたら:

(A|B)~(A~^B)

foo*たとえば、一致するが両方とも一致しないファイルを見つけるには、*.txt次のようにします。

そしてkshまたはbash -o extglob(またはzsh -o kshglob):

files=(!(!(foo*|*.txt)|!(!(foo*)|!(*.txt))))

または以下を使用してzsh -o extendedglob

files=(^(^(foo*|*.txt)|^(^foo*|^*.txt)))

または:

files=((foo*|*.txt)~(foo*~^*.txt))

POSIXシェルには、バイナリ(ビット単位)のXOR算術演算子があります。そのまま$(( 1 ^ 2 ))に拡張されます。3XOR(0b01, 0b10)

xorしたがって、両方のシェルコードの評価の1つだけがtrueを返す場合は、trueを返す関数を次のように定義できます。

xor() {
  eval "$1"; s1=$((!$?))
  eval "$2"; s2=$((!$?))
  [ "$((s1 ^ s2))" -ne 0 ]
}
match() {
  case $1 in
    ($2) true;;
    (*)  false;;
  esac
}
for file in *; do
  if
    xor 'match "$file" "foo*"' \
        'match "$file" "*.txt"' &&
  then
    printf '%s\n' "$file"
  fi
done

関連情報