Am file.txt pe care trebuie să îl citesc într-un tablou Bash. Apoi, trebuie să elimin spații, ghilimele duble și toate, cu excepția primei virgule din fiecare intrare . Iată cât de departe am ajuns:
$ 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|
Care funcționează excelent, cu excepția situației virgulei. Sunt conștient de faptul că există mai multe moduri de a jupui această pisică, dar datorită scriptului mai mare din care face parte, aș vrea să folosesc înlocuirea parametrilor pentru a ajunge aici:
|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Este posibil prin substituirea parametrilor?
Comentarii
- Există vreun motiv pentru care trebuie să păstrați textul în o matrice și de ce nu poți ‘ să lași de ex.
awk
saused
procesează datele? - @Jeff – Buclarea peste matrice va fi o coșmar de implementat în scriptul mai mare pe care ‘ lucrez.
- @JonRed Nu ‘ nu știu ce faceți, deci este ‘ complet posibil să nu aveți de ales în această materie, dar, în general, atunci când vă aflați în acrobații complexe de șiruri în shell, ca ‘ este o indicație foarte bună că ar trebui să utilizați un limbaj de programare propriu-zis. Shell-ul nu este conceput ca limbaj de programare și, deși poate fi folosit ca unul, nu este într-adevăr ‘ o idee bună pentru lucruri mai complexe. Vă îndemn insistent să luați în considerare trecerea la perl sau python sau la orice alt limbaj de scriptare.
- @terdon Este ‘ amuzant, tocmai am terminat de spus aproape exact același lucru și colegului meu înainte să citesc această postare. Practic am spus că aceasta este versiunea finală a acestui script și că orice alte cerințe vor necesita rescrierea în Perl. Deci da, sunt de acord cu siguranță
Răspuns
Aș elimina ceea ce trebuie să eliminați folosind înainte încărcarea în matrice (rețineți și numele minusculelor variabilelor, în general, cel mai bine este să evitați variabilele cu majuscule în scripturile shell):
#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done
Aceasta produce următoarea ieșire din fișierul dvs. de exemplu:
$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Dacă într-adevăr trebuie să utilizați parametrul substituție, încercați ceva de genul acesta:
#!/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
Comentarii
Răspuns
Din câte văd, nu este nevoie să citiți-l într-o matrice bash
pentru a crea acea ieșire:
$ 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|
sed
expresia șterge spații și ghilimele duble, înlocuiește prima virgulă cu un spațiu (nu există alte spații în șir în acest moment), șterge toate celelalte virgule, restabilește prima virgulă, și prependează și adaugă datele suplimentare .
Alternativ, cu GNU sed
:
sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file
(standard sed
nu acceptă combinația 2
și g
ca steaguri către s
comanda).
Comentarii
- cu GNU sed, puteți utiliza
's/,//2g
pentru a elimina virgulele, începând cu a doua - Și ultimele 2 s /// comenzi pot fi
s/.*/|ELEMENT|&|/
dar ar putea fi un efort mai mare pentru sed. - @glennjackman Posibil, dar pare destul de îngrijit.
- Da, aceasta face parte dintr-un script mai mare. Matricea este necesară, nu doar pentru ieșire. De aici și interesul meu pentru substituirea parametrilor. Aș putea face o buclă peste matrice cu asta, dar acesta va fi un coșmar de implementat. Terndon a oferit o soluție fără buclă folosind sed, pe care ‘ probabil că o să recurg dacă substituirea parametrilor este interzisă.
- Dacă nu aș fi ‘ legat de utilizarea unei matrice, totuși aceasta ar fi cea mai bună soluție.
Răspuns
ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}"
50,need2
Ieșiți din obișnuința de a folosi numele variabilelor ALLCAPS. În cele din urmă vă veți ciocni cu o variabilă crucială de „sistem”, cum ar fi PATH, și vă va rupe codul.
Comentarii
- Nu substituirea parametrilor. DAR, nu știam că numele variabilelor ALLCAPS erau un obicei prost în Bash. Faceți un punct bun, unul pe care un googling rapid îl confirmă cu siguranță. Vă mulțumesc că mi-ați îmbunătățit stilul! 🙂
- Am ‘ răspuns la întrebări în care persoana respectivă a scris
PATH=something; ls $PATH
și apoi m-am întrebat desprels: command not found
. - Există aproape o sută de variabile încorporate care sunt denumite în toate majusculele (faceți clic pe această pagină manuală link ) pentru a vedea …
Răspuns
[Acesta este, în esență, un program mai complet dezvoltat versiunea răspunsului glenn jackmann ]
Construirea unui tablou asociativ din cheia și valoarea dezbrăcate, folosind prima virgulă ca separator:
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|
Răspuns
Puteți face o buclă peste matrice și puteți utiliza o variabilă intermediară:
for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done
Acest lucru atribuie rest
porțiunea după prima virgulă; apoi concatenăm trei piese înapoi în original variabilă:
- porțiunea dinaintea primei virgule
- o virgulă
- înlocuirea în
rest
a fiecărei virgule fără nimic
Comentarii
- Acesta a fost primul meu gând și este suficient de simplu pentru exemplu, dar aceasta face parte dintr-un script mai mare în care matricea este masivă și există ‘ bucle deja și ar fi un lucru întreg. Acest lucru ar funcționa cu siguranță, dar ar fi foarte dificil de implementat în proiectul mai mare pe care
m lucrez.
RANDOMTEXTTHATWILLNEVERBEINTHEFILE
.