如何在 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//:/ })

哪个有效,但并不真正兼容。我可以使用以下行来区分 shell:

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//:/ })

是错误的,因为它在替换后应用 split+glob:

你想要:

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.

zsh如果该代码处于shksh仿真模式,则该代码也可以在 中运行。如果您的目标是编写与bash和兼容的代码zsh,您可能需要使用 ksh 语法编写它并确保将其zsh放入ksh

要测试 shell 是否为bashzsh,您需要测试是否存在$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

相关内容