Teilen Sie eine einzelne Zeichenfolge mit NUR Bash in ein Zeichenarray auf

9

Ich möchte aufgeteilt 'hello'in h e l l onur bash unter Verwendung in einem Array, konnte ich es mit in sed tun , sed 's/./& /g'aber ich möchte wissen , wie eine Zeichenfolge in ein Array in Bash aufzuspalten , wenn ich nicht weiß , was das Trennzeichen wäre, oder das Trennzeichen ist jedes einzelnes Zeichen. Ich glaube nicht, dass ich ${i// /}ohne etwas Kreativität verwenden kann, da das Trennzeichen ein Unbekannter ist, und ich glaube nicht, dass dieser Ausdruck Regex akzeptiert. Ich habe versucht, BASH_REMATCH mit [[string = ~ ([az].). *]] Zu verwenden, aber es funktioniert nicht wie erwartet. Was ist der richtige Weg, um nur Bash zu verwenden, um eine string.split()Art von Verhalten zu erreichen? Der Grund ist, dass ich versuche, das rev-Dienstprogramm in allen Bashs zu schreiben:

  while read data; do
  word=($(echo $data|tr ' ' '_'|sed 's/./& /g'))
  new=()
  i=$((${#word[@]} - 1))
  while [[ $i -ge 0 ]]; do
    new+=(${word[$i]})
    (( i-- ))
  done
  echo ${new[@]}|tr -d ' '|tr '_' ' '
  done

Aber ich habe tr und sed verwendet, ich möchte wissen, wie man den Split richtig macht, und dann werde ich ihn so reparieren, dass alles Bash ist. Nur zum Spaß.

Gregg Leventhal
quelle
Angesichts der Größe des Stapelüberlaufs müssen standortübergreifende Duplikate vorhanden sein. Ein Kandidat ist Bash: String in Zeichenarray aufteilen .
Peter Mortensen
[[ $string =~ ${string//?/(.)} ]]wird BASH_REMATCH[]nach Bedarf eingestellt, siehe meine Antwort auf die Frage, auf die Peter Mortensen verweist, für eine Erklärung.
mr.spuratic

Antworten:

12
s="hello"
declare -a a   # define array a
for ((i=0; i<${#s}; i++)); do a[$i]="${s:$i:1}"; done
declare -p a   # print array a in a reusable form

Ausgabe:

deklariere -aa = '([0] = "h" [1] = "e" [2] = "l" [3] = "l" [4] = "o")'

oder (bitte beachten Sie die Kommentare)

s="hello"
while read -n 1 c; do a+=($c); done  <<< "$s"
declare -p a

Ausgabe:

deklariere -aa = '([0] = "h" [1] = "e" [2] = "l" [3] = "l" [4] = "o")'
Cyrus
quelle
1
Das zweite ist nett, aber es funktioniert nur (in diesem Fall), weil Sie nicht "$ c" zitieren, so dass Leerzeichen gelöscht und Sterne in $ s erweitert werden.
Rici
2
Die zweite Option sollte sein : while read -N 1 c; do a+=("$c"); done <<< "$s". Das -Nerlaubt, sogar Zeilenumbrüche zu lesen, und die Anführungszeichen ("$c")vermeiden die Erweiterung des Pfadnamens (und einige andere Probleme).
1
Wenn die letzte neue Zeile korrigiert werden muss, ändern Sie natürlich die angegebene Zeile in: while read -N 1 c; do a+=("$c"); done <<< "$s"xund löschen Sie dann die letzte neue Zeile und das hinzugefügte x : unset a[${#a[@]}-1]; unset a[${#a[@]}-1].
4

Um die Zeichenfolge mit einem Nulltrennzeichen in ein Zeichenarray aufzuteilen, können Sie:

str='hello'
arr=()
i=0
while [ "$i" -lt "${#str}" ]; do
  arr+=("${str:$i:1}")
  i=$((i+1))
done

printf '%s\n' "${arr[@]}"

Mit einem anderen Trennzeichen als null können Sie:

set -f
str='1,2,3,4,5'
IFS=',' arr=($str)
printf '%s\n' "${arr[@]}"
cuonglm
quelle
Wenn eingestellt werden IFSkann, können Sie einfach : IFS=',' arr=($str).
Muru
2
@muru: In diesem Fall wirst du mit Glob stecken bleiben. Aktualisiert mit Deaktivierung von Glob.
Cuonglm
@ BinärZebra: Ah, ja, mein schlechtes, fehlendes Zitat. Es wurde behoben, danke.
Cuonglm
2

Nur zum Spaß (und andere Muscheln) andere Variante:

word=hello
unset letter
while [ ${#word} -gt 0 ]
do
    rest=${word#?}
    letter[${#letter[*]}]=${word%$rest}
    word=$rest
done

Und prüfe

for l in "${!letter[@]}"
do
    echo "letter [$l] = ${letter[l]}"
done

wird gedruckt

letter [0] = h
letter [1] = e
letter [2] = l
letter [3] = l
letter [4] = o
Costas
quelle
0

Methode 1:

Einzeiler:

s="hello"
for ((i=0;i<${#s};i++)); do result[$i]="${s:i:1}"; done
echo ${result[@]}

Erweiterter Code:

s="hello"                   # Original string.

for ((i=0;i<${#s};i++)); do # For i=0; i<(length of s); i++
    result[$i]="${s:i:1}"       # result[i] is equal to the i th character of $s
done                        # End of the loop

echo ${result[@]} # Print all elements of $result.

Methode 2:

Einzeiler:

s="hello"
var=($(while read -n 1; do printf "$REPLY "; done <<< "$s"))
echo "${var[@]}"

Erweiterter Code:

s="hello" # Original string.

while read -n 1; do # Read chraracter by character the string.
    space_separated=$(printf "$space_separated $REPLY") # $space_separated is equal to it plus the current character.
done <<< "$s" # Pass the string to the loop

result=($space_separated) # Split $space_separated into an array.

echo "${result[@]}" # Print all elements of $result.

Vielen Dank an @cuonglm durch seinen Vorschlag. Tatsächlich
können Sie $REPLYdie Standardvariable verwenden, in readder die Eingabe gelesen wird.

Helio
quelle
1
Sie können $REPLYanstelle von charVariablen verwenden.
Cuonglm