bash / zshで ':'文字を使用して文字列を分割する方法は?

bash / zshで ':'文字を使用して文字列を分割する方法は?

文字列(変数)を分割する方法を探しています。:

他のソースから次のコマンドが見つかりました。

str="part1=part2=part3"
parts=(${(@s:=:)str})
echo ${#parts[@]}

:しかし、同じシーケンスのエスケープ方法が見つかりません。

parts=(${(@s:::)str})  #Not working
parts=(${(@s:\::)str}) #Not working

Bashの場合は、次のものが見つかりました。

parts=(${str//:/ })

動作しますが、実際には互換性がありません。次の行を使用してシェルを区別できます。

if [ -z "$(ps -p $$| grep zsh)" ]; then
    echo "This is bash (Use bash solution here)"
else
    echo "This is zsh (Use Zsh solution here)"
fi

しかし、いくつかの代替ソリューションは互換性がありますか?実行可能なソリューションはすでに成功しています。

ベストアンサー1

これ:

あなたはそれを使用することができます:

parts=(${(s/:/)str})

次のようないくつかの一般的な文字ペアもサポートされています。

parts=(${(s[:])str})

このフラグを使用して@空の要素を保持するには、次のものを引用する必要があります。

parts=("${(@s[:])str}")

そうでなければ@

このような変数を扱いたい場合$PATH$LD_LIBRARY_PATHtypeset -T結ぶ配列変数をスカラー変数として:

$ typeset -T str str_array
$ str='a::b'
$ typeset -p str
typeset -T str str_array=( a '' b )

zshデフォルトではバインドされます$path$PATH例:csh/tcsh

バッシュ

parts=(${str//:/ })

交換後に分割+グローブを適用するため、間違っています。:

あなたが望むもの:

IFS=:            # split on : instead of default SPC TAB NL
set -o noglob    # disable glob
parts=( $str"" ) # split+glob (leave expansion unquoted), preserve trailing
                 # empty part.

zshshコードがエミュレーションモードの場合、kshコードは でも実行されます。あなたの目標はbash互換性のあるコードを書くことであり、ksh構文を使って書くことをzsh望むかもしれません。zshksh

シェルがbashあるかどうかをテストするには、変数があるかどうかをテストするzsh必要があります。$BASH_VERSION$BASH_VERSINFO$ZSH_VERSION

split() { # args: string delimiter result_var
  if
    [ -n "$ZSH_VERSION" ] &&
      autoload is-at-least &&
      is-at-least 5.0.8 # for ps:$var:
  then
    eval $3'=("${(@ps:$2:)1}")'
  elif
    [ "$BASH_VERSINFO" -gt 4 ] || {
      [ "$BASH_VERSINFO" -eq 4 ] && [ "${BASH_VERSINFO[1]}" -ge 4 ]
      # 4.4+ required for "local -"
    }
  then
    local - IFS="$2"
    set -o noglob
    eval "$3"'=( $1"" )'
  else
    echo >&2 "Your shell is not supported"
    exit 1
  fi
}

split "$str" : parts

おすすめ記事