Zeichenfolge im Shell-Skript in Array aufteilen

Zeichenfolge im Shell-Skript in Array aufteilen

Ich versuche beispielsweise, einen String string=11111001in ein Array umzuwandeln, auf das ich zugreifen kann, indem ich den entsprechenden Array-Index aufrufe, wie

arr[0]=1, arr[1]=0

Ich habe keine Erfahrung mit Shell-Skripten und nach dem, was ich gelesen habe, gibt es keinen Trenner. Ich stecke fest.

Kann mir jemand helfen?

Antwort1

bashhat bereits eine Form davon durch String-Slicing:

$ word="word"
$ printf "%s\n" "${word:0:1}"
w
$ printf "%s\n" "${word:1:1}"
o

Die Syntax hierfür ist ${variable:start:length}und gibt den nächsten zurücklengthZeichen beginnend beistartᵗʰ-Zeichen (nullindiziert).

$ printf "%s\n" "${word:2:2}"
rd

Antwort2

Der Vollständigkeit halber können Sie mit zsheinen String in folgende Teile aufteilen:

es istCharakterBestandteile:

chars=( ${(s[])string} )

(wenn $stringBytes enthalten sind, die nicht Teil gültiger Zeichen sind, wird jedes davon trotzdem als separates Element gespeichert)

es istByteBestandteile

Sie können dasselbe tun, aber nachdem Sie dieMultibyteOption, beispielsweise lokal in einer anonymen Funktion:

(){ set -o localoptions +o multibyte
  bytes=( ${(s[])string} )
}

es istGraphemclusterBestandteile.

Sie können die Fähigkeit von PCRE nutzen, sie mit Folgendem abzugleichen \X:

zmodload zsh/pcre
(){
  graphemes=()
  local rest=$string match
  pcre_compile -s '(\X)\K.*'
  while pcre_match -v rest -- "$rest"; do
    graphemes+=($match[1])
  done
}

(dabei wird davon ausgegangen, dass die Eingabe Text enthält, der ordnungsgemäß im Charmap des Gebietsschemas codiert ist).


Mit string=$'Ste\u0301phane'ergeben sich:

chars=( S t e ́ p h a n e )
bytes=( S t e $'\M-L' $'\M-\C-A' p h a n e )
graphemes=( S t é p h a n e )

Da der eGraphemcluster + U+0301 (der auf Anzeigegeräten normalerweise dasselbe darstellt wie das évorkomponierte Äquivalent U+00E9) aus 2 Zeichen besteht (U+0065 und U+0301), ist in Gebietsschemas, die UTF-8 als Zeichenzuordnung verwenden, das erste auf einem Byte (0x65) und das zweite auf zwei Bytes (0xcc 0x81, auch bekannt als Meta-L und Meta-Ctrl-A) codiert.

Bei Zeichenfolgen wie Ihren, die nur aus ASCII-Zeichen bestehen 11111001, sind alle drei gleichwertig.

Beachten Sie, dass zshwie in allen anderen Shells außer ksh/bash die Array-Indizes bei 1 und nicht bei 0 beginnen.

Antwort3

Sie können die Zeichenfolge in einzelne Zeichen aufteilen:

string=11111001
echo "$string" | grep -o .

und lesen Sie sie als Array zurück:

readarray -t arr <<<"$(grep -o . <<<"$string")"

Dann würde sich natürlich jedes Zeichen an jedem Index des arrArrays befinden.

$ declare -p arr
declare -a arr=([0]="1" [1]="1" [2]="1" [3]="1" [4]="1" [5]="0" [6]="0" [7]="1")

Aber warum sollte ein neues Array erstellt werden, wenn Bash auf jedes einzelne Zeichen direkt wie folgt zugreifen könnte:

$ string=11111001
echo "${string:5:1}" "${string:7:1}"
0 1

Lesen Sie mehr darüber ${parameter:offset:length}in man bash.

Antwort4

Da in den Variablen von bash4.4+ bashohnehin keine NUL-Zeichen gespeichert werden können, können Sie zum Aufteilen ein anderes Dienstprogramm aufrufen und das Ergebnis NUL-getrennt ausgeben, das Sie mit in ein Array einlesen können readarray -td ''.

Wenn Ihr System mit der GNU-Implementierung von ausgestattet ist grep, können Sie Folgendes tun:

readarray -td '' bytes < <(printf %s "$string" | LC_ALL=C grep -zo .)
readarray -td '' chars < <(printf %s "$string" | grep -zo .)
readarray -td '' graphemes < <(printf %s "$string" | grep -zPo '\X')

Alle außer dem ersten überspringen Bytes, die nicht Teil gültiger Zeichen im Gebietsschema sind (zumindest mit GNU grep3.4). Beispielsweise string=$'Ste\u0301phane \\\xf0\x80z.'ergibt sich mit (der nachfolgende Teil bildet kein gültiges UTF-8) in einem UTF-8-Gebietsschema:

declare -a bytes=([0]="S" [1]="t" [2]="e" [3]=$'\314' [4]=$'\201' [5]="p" [6]="h" [7]="a" [8]="n" [9]="e" [10]=" " [11]="\\" [12]=$'\360' [13]=$'\200' [14]="z" [15]=".")
declare -a chars=([0]="S" [1]="t" [2]="e" [3]="́" [4]="p" [5]="h" [6]="a" [7]="n" [8]="e" [9]=" " [10]="\\" [11]="z" [12]=".")
declare -a graphemes=([0]="S" [1]="t" [2]="é" [3]="p" [4]="h" [5]="a" [6]="n" [7]="e" [8]=" " [9]="\\" [10]="z" [11]=".")

Wenn Sie sich nicht auf einem GNU-System befinden und $stringgültigen UTF-8-Text enthalten, können Sie perlstattdessen Folgendes verwenden:

readarray -td '' bytes < <(perl -0le 'print for split "", shift' -- "$string")
readarray -td '' chars < <(perl -CSA -0le 'print for split "", shift' -- "$string")
readarray -td '' graphemes < <(perl -CSA -0le 'print for shift =~ /\X/g' -- "$string")

verwandte Informationen