Bashの `expr index "abcdefghijklmnopqrstuvwxyz" xyzd`に対応するZsh

Bashの `expr index "abcdefghijklmnopqrstuvwxyz" xyzd`に対応するZsh

Zshはbashと同じですか?

expr index "abcdefghijklmnopqrstuvwxyz" xyzd

部分文字列のインデックスを見つけようとしています。

答え1

zsh非標準のexpr使用法(btwには関係ありません)の組み込みの代替案を探している場合は、bash次のことができます。

$ a=abcdefghijklmnopqrstuvwxyz b=xyzd
$ echo ${a[(i)[$b]]}
4

を使用するとiインデックスを取得できます最初一致します(一致するものがない場合は、干し草の山の長さを追加します)。代わりにI、最後の一致を取得します(または一致がない場合は0)。

POSIXに似たシェルを使用(bashおよび含むzsh

$ s=${a%%[$b]*}
$ echo "$(($#s + 1))"
4

答え2

GNU coreutilsパッケージの実装は、exprどのシェルを使用しても同じ方法で使用できる外部ユーティリティです。

存在するzsh

expr index "abcdefghijklmnopqrstuvwxyz" xyzd

4シェルbashや他のシェルと同様に返されます。

indexGNUの仕事はexpr次のとおりです。基準exprこれはexpr: syntax error、特定の実装がないシステムでバグが発生する可能性があることを意味しますexpr。どのシェルを使用するかは問題ではありません。

答え3

expr index "abcdefghijklmnopqrstuvwxyz" xyzd

部分文字列のインデックスを見つけようとしています。

部分文字列インデックスまたは文字インデックス?部分文字列(文字列には存在しません)ではなく、expr index2番目のグループ、つまり上記の最初の文字が見つかった文字を探します。dxyzd

部分文字列の位置を見つけるには、標準シェルで次のようにします。

haystack=abcdefghijklmnopqrstuvwxyz
needle=jkl
x=${haystack%%$needle*};

これでx、その部分文字列の前の文字列部分が含まれます"${#x}"(この場合は0から始まる位置)。jkl9

文字セット内の文字(バイト)の位置を見つけるには、次のように使用できます。

haystack=abcdefghijklmnopqrstuvwxyz
needle=xqe;
x=${haystack%%[$needle]*}; 

ここは"${#x}"4です。 2つの方法の欠点は、検索中の文字列/文字が見つからない場合はx全体を含むため、一致するものがあるかどうかを確認するには、全長(ゼロではない)と比較するhaystack必要があります。"${#x}"haystack

haystack=abcdefghijklmnopqrstuvwxyz
needle=qqq
x=${haystack%%$needle*}
if [ "${#x}" = "${#haystack}" ]; then echo "$needle not found"; fi

答え4

Kusalanandaがすでに彼のコメントで指摘したように、exprzshでも使用できますが、Zsh組み込みこれを行う方法。

答えは「いいえ」ですが、以下の内容が含まれています。

v="abcdefghijklmnopqrstuvwxyz"
i=${(SB)v#cdef}

これは3に設定されますi。しかし、これが同じように機能する理由は2つありますexpr index

あなたが提供した例では、あなたは以下を検索しています。XYZD、これは文字列には存在しませんが、文字列は次に終了するためXYZexpr「d」を正常に削除し、一致を返します。この点でZshの行動はより合理的であると主張するかもしれませんが、もちろんこれが重要な問題であれば、私はZshに固執します。

Zshが別の別の理由は、${(SB)v#...}文字列が存在しない場合は1を返すことです。いいえマッチ。例えば、

echo ${(SB)v#a}
echo ${(SB)v#7}

1を返します。これだけでは、不一致と最初の文字の一致を区別することはできません。考えられる解決策の1つは、レースの位置と長さを計算することです。

# N returns the length of the match
index_and_length=${(SBN)v#...}
# index_and_length contains the index, a space, and the length
if [[ ${index_and_length#* } == 0 ]]
then
  echo no match
else
  index=${index_and_length% *}
  echo match at index $index
fi

UDPATE:この投稿のコメントでわかるように、私が間違って理解したexpr indexため、答えは不適切です。ただし、検索する「文字列」がグローバルパターンであるため、これを調整できます。したがって、角かっこが操作を実行します。

# Search for the first occurance of one of the letters x y z d
index_and_length=${(SBN)v#[xyzd]}

関連情報