Verwenden der Parametersubstitution in einem Bash-Array

Ich habe die Datei file.txt, die ich in ein Bash-Array einlesen muss. Dann muss ich Leerzeichen, doppelte Anführungszeichen und alle bis auf das erste Komma in jedem Eintrag entfernen. So weit bin ich gekommen:

$ cat file.txt 10,this 2 0 , i s 30,"all" 40,I 50,n,e,e,d,2 60",s e,e" $ cat script.sh #!/bin/bash readarray -t ARRAY<$1 ARRAY=( "${ARRAY[@]// /}" ) ARRAY=( "${ARRAY[@]//\"/}" ) for ELEMENT in "${ARRAY[@]}";do echo "|ELEMENT|$ELEMENT|" done $ ./script.sh file.txt |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,n,e,e,d,2| |ELEMENT|60,se,e| 

Was bis auf die Kommasituation hervorragend funktioniert. Ich bin mir bewusst, dass es mehrere Möglichkeiten gibt, diese Katze zu häuten, aber aufgrund des größeren Skripts, zu dem dies gehört, würde ich gerne die Parametersubstitution verwenden, um hierher zu gelangen:

|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

Ist dies über die Parametersubstitution möglich?

Kommentare

  • Gibt es einen Grund, den Text beizubehalten? ein Array, und warum Sie ‚ nicht z awk oder sed führt die Verarbeitung der Daten durch?
  • @Jeff – Durchlaufen des Arrays erfolgt a Albtraum in das größere Skript zu implementieren Ich ‚ arbeite daran.
  • @JonRed Ich weiß nicht, was ‚ Sie tun es, also ist es durchaus möglich, dass Sie ‚ keine Wahl haben, aber im Allgemeinen, wenn Sie feststellen, dass Sie solch komplexe String-Akrobatik in der Shell ausführen, dass ‚ ist ein sehr guter Hinweis darauf, dass Sie eine tatsächliche Programmiersprache verwenden sollten. Die Shell ist nicht als Programmiersprache konzipiert, und obwohl sie als eine verwendet werden kann, ist sie für komplexere Dinge keine ‚. Ich fordere Sie dringend auf, in Betracht zu ziehen, zu Perl, Python oder einer anderen Skriptsprache zu wechseln.
  • @terdon Es ist lustig, ich habe gerade fast genau das gesagt Das Gleiche gilt für meinen Kollegen, bevor ich diesen Beitrag lese. Ich sagte im Grunde, dass dies die endgültige Version dieses Skripts ist und dass alle weiteren Anforderungen ein erneutes Schreiben in Perl erfordern. Also ja, ich stimme definitiv zu

Antwort

Ich würde entfernen, was Sie mit sed vor dem Laden in das Array (beachten Sie auch die Variablennamen in Kleinbuchstaben, im Allgemeinen ist es am besten, großgeschriebene Variablen in Shell-Skripten zu vermeiden):

#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done 

Dies erzeugt die folgende Ausgabe in Ihrer Beispieldatei:

$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

Wenn Sie wirklich Parameter verwenden müssen Ersetzen Sie Folgendes:

#!/bin/bash readarray -t array< "$1" array=( "${array[@]// /}" ) array=( "${array[@]//\"/}" ) array=( "${array[@]/,/\"}" ) array=( "${array[@]//,/}" ) array=( "${array[@]/\"/,}" ) for element in "${array[@]}"; do echo "|ELEMENT|$element|" done 

Kommentare

  • @JonRed Ich habe eine Version mit Parameter hinzugefügt Substitution, aber es ist ‚ komplex, umständlich und hässlich. Dies in der Shell zu tun, ist sehr selten eine gute Idee.
  • Beachten Sie, dass diese Zeichen verfügbar werden, wenn Sie ‚ sowohl Leerzeichen als auch doppelte Anführungszeichen entfernt haben anstelle Ihrer RANDOMTEXTTHATWILLNEVERBEINTHEFILE zu verwenden.
  • @Kusalananda Ja, ich habe gerade Ihre Antwort gelesen. Hätte daran denken sollen! Danke 🙂
  • Beantwortet direkt die Frage, zeigt, warum meine bevorzugte Lösung nicht ‚ t ideal ist und bietet die praktikabelste Alternative. Sie gewinnen, beste Antwort.

Antwort

Soweit ich sehen kann, besteht keine Notwendigkeit Lesen Sie es in ein bash -Array, um diese Ausgabe zu erstellen:

$ sed "s/[ "]//g; s/,/ /; s/,//g; s/ /,/; s/.*/|ELEMENT|&|/" <file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see| 

Die sed löscht Leerzeichen und doppelte Anführungszeichen, ersetzt das erste Komma durch ein Leerzeichen (zu diesem Zeitpunkt befinden sich keine weiteren Leerzeichen in der Zeichenfolge), löscht alle anderen Kommas, stellt das erste Komma wieder her und stellt die zusätzlichen Daten voran und hängt sie an .

Alternativ mit GNU sed:

sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file 

(Standard sed unterstützt die Kombination von 2 und g als Flags für Befehl).

Kommentare

  • Mit GNU sed können Sie 's/,//2g verwenden Um Kommas zu entfernen, beginnend mit dem 2.
  • Und die letzten 2 s /// Befehle können s/.*/|ELEMENT|&|/ aber das mag für sed mehr Aufwand sein.
  • @glennjackman Möglicherweise, aber es sieht ziemlich ordentlich aus.
  • Ja, das ist Teil eines größeren Skripts. Das Array ist nicht nur für die Ausgabe erforderlich. Daher mein Interesse an der Parametersubstitution. Ich könnte das Array damit durchlaufen, aber das wird ein Albtraum sein, den es zu implementieren gilt. Terndon lieferte eine schleifenfreie Lösung mit sed, auf die ich ‚ wahrscheinlich zurückgreifen werde, wenn die Parametersubstitution nicht möglich ist.
  • Wenn ich nicht ‚ ist nicht an die Verwendung eines Arrays gebunden, dies wäre jedoch die beste Lösung.

Antwort

ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}" 
50,need2 

Machen Sie es sich nicht mehr zur Gewohnheit, ALLCAPS-Variablennamen zu verwenden. Sie werden schließlich mit einer entscheidenden „System“ -Variablen wie PATH kollidieren und Ihren Code brechen.

Kommentare

  • Keine Parametersubstitution. ABER ich wusste nicht, dass ALLCAPS-Variablennamen in Bash eine schlechte Angewohnheit waren. Sie machen einen guten Punkt, den ein flüchtiges Googeln definitiv bestätigt. Danke, dass du meinen Stil verbessert hast! 🙂
  • Ich ‚ habe Fragen beantwortet, bei denen die Person PATH=something; ls $PATH geschrieben und mich dann über die ls: command not found Fehler.
  • Es gibt fast hundert integrierte Variablen, die in Großbuchstaben benannt sind (klicken Sie sich durch dieser Manpage Link ) um zu sehen …

Antwort

[Dies ist im Wesentlichen eine vollständigere version von glenn jackmanns antwort ]

Erstellen eines assoziativen Arrays aus dem entfernten Schlüssel und Wert unter Verwendung des ersten Kommas als Trennzeichen:

declare -A arr while IFS=, read -r k v; do arr["${k//[ \"]}"]="${v//[ ,\"]}"; done < file.txt for k in "${!arr[@]}"; do printf "|ELEMENT|%s,%s|\n" "$k" "${arr[$k]}" done |ELEMENT|20,is| |ELEMENT|10,this| |ELEMENT|50,need2| |ELEMENT|40,I| |ELEMENT|60,see| |ELEMENT|30,all| 

Antwort

Sie können das Array durchlaufen und eine Zwischenvariable verwenden:

for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done 

Dies weist rest den Teil nach dem ersten Komma zu. Anschließend verknüpfen wir drei Teile wieder mit dem Original Variable:

  • der Teil vor dem ersten Komma
  • ein Komma
  • die Ersetzung in rest jedes Kommas durch nichts

Kommentare

  • Dies war mein erster Gedanke und ist für das Beispiel einfach genug, aber dies ist Teil eines größeren Skripts, in dem das Array massiv ist und ‚ bereits Schleifen enthält, und es wäre eine ganze Sache. Dies würde definitiv funktionieren, wäre aber sehr umständlich in dem größeren Projekt zu implementieren, an dem ich ‚ arbeite.
  • Fair genug; Ich habe nur versucht, innerhalb der Grenzen zu antworten (nur Parametererweiterung).

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.