Wie teile ich einen String nach ':' in bash / zsh?

Oct 13 2020

Ich suche nach einer Möglichkeit, eine Zeichenfolge (Variable) :auf kompatible Weise zwischen bash und zsh nach Zeichen aufzuteilen .

Aus verschiedenen Quellen habe ich den folgenden Befehl gefunden:

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

Ich konnte jedoch nicht den Weg finden, um :für dieselbe Sequenz zu entkommen

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

Für Bash habe ich folgendes gefunden:

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

Was funktioniert, ist aber nicht wirklich kompatibel. Ich könnte die folgende Zeile verwenden, um die Shell zu unterscheiden:

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

Aber vielleicht ist eine alternative Lösung kompatibel? Jede funktionierende Lösung ist bereits ein Gewinn.

Antworten

9 StéphaneChazelas Oct 13 2020 at 11:51

Das :gibt es ein beliebiges Zeichen:

Sie können verwenden:

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

Einige gängige Zeichenpaare werden ebenfalls unterstützt wie:

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

Wenn Sie das @Flag verwenden möchten, um leere Elemente beizubehalten, müssen Sie Folgendes zitieren:

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

Ansonsten @macht es keinen Unterschied.

Wenn es darum geht, Variablen wie $PATH/ $LD_LIBRARY_PATH... zu verarbeiten, sehen Sie auch, typeset -Twelche eine Array-Variable an eine skalare Variable bindet :

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

zshtut Krawatte $pathzu $PATHstandardmäßig (wie in csh/ tcsh).

Bash's

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

Ist falsch, da Split + Glob nach dem Ersetzen durch :SPC angewendet wird.

Du würdest wollen:

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.

Dieser Code würde auch in zsh, wenn es in war shoder kshEmulationsmodus. Wenn Ihr Ziel zu schreiben Code kompatibel zu beiden ist bashund zsh, können Sie es schreiben KSH Syntax und stellen Sie sicher , dass zshin gesetzt wird ksh(bis zu einem gewissen Funktion nur lokal möglicherweise) Emulation , wenn es zu interpretieren.

Um zu testen, ob die Shell bashoder ist zsh, würden Sie das Vorhandensein der $BASH_VERSION/ $BASH_VERSINFOoder $ZSH_VERSIONVariablen testen .

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