![Zeichenfolge im Shell-Skript in Array aufteilen](https://rvso.com/image/192230/Zeichenfolge%20im%20Shell-Skript%20in%20Array%20aufteilen.png)
Ich versuche beispielsweise, einen String string=11111001
in 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
bash
hat 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ücklength
Zeichen beginnend beistart
ᵗʰ-Zeichen (nullindiziert).
$ printf "%s\n" "${word:2:2}"
rd
Antwort2
Der Vollständigkeit halber können Sie mit zsh
einen String in folgende Teile aufteilen:
es istCharakterBestandteile:
chars=( ${(s[])string} )
(wenn $string
Bytes 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 e
Graphemcluster + 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 zsh
wie 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 arr
Arrays 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 bash
4.4+ bash
ohnehin 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 grep
3.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 $string
gültigen UTF-8-Text enthalten, können Sie perl
stattdessen 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")