har jag file.txt som jag behöver läsa in i en Bash-array. Då måste jag ta bort mellanslag, dubbla citat och alla utom det första komma i varje post . Här är hur långt jag har kommit:
$ 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|
Vilket fungerar bra förutom kommasituationen. Jag är medveten om att det finns flera sätt att hyra den här katten, men på grund av det större skriptet som det här är en del av skulle jag verkligen vilja använda parameterbyte för att komma hit:
|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Är detta möjligt via parameterbyte?
Kommentarer
- Finns det någon anledning att du behöver behålla texten en matris och varför du inte kan ’ t låta t.ex.
awk
ellersed
gör bearbetningen av data? - @Jeff – Looping över matrisen blir en mardröm att implementera i det större skriptet som jag ’ arbetar på.
- @JonRed Jag vet inte ’ vet inte vad du gör, så det är ’ helt möjligt att du kanske inte har något val i frågan, men i allmänhet, när du befinner dig att göra så komplexa strängakrobatik i skalet, att ’ är en mycket bra indikation på att du ska använda ett verkligt programmeringsspråk. Skalet är inte utformat som ett programmeringsspråk, och även om det kan användas som ett, är det verkligen inte ’ inte en bra idé för mer komplexa saker. Jag uppmanar dig starkt att överväga att byta till perl eller python eller något annat skriptspråk.
- @terdon Det ’ är roligt, jag har precis gjort det att säga nästan exakt samma sak till min kollega innan jag läste det här inlägget. Jag sa i princip att detta är den slutliga versionen av detta manus och att ytterligare krav kommer att kräva omskrivning i Perl. Så ja, jag håller definitivt med
Svar
Jag skulle ta bort det du behöver ta bort med sed
innan laddas in i matrisen (notera också små variabelnamn, i allmänhet är det bäst att undvika stora variabler i skalskript):
#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done
Detta ger följande utdata i din exempelfil:
$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Om du verkligen måste använda parameter substitution, prova något så här:
#!/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
Kommentarer
Svar
Så vitt jag kan se finns det inget behov av läs den i en bash
-matris för att skapa den utgången:
$ 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
uttryck raderar mellanslag och dubbla citattecken, ersätter det första kommatecknet med ett mellanslag (det finns inga andra mellanslag i strängen vid denna tidpunkt), raderar alla andra kommatecken, återställer det första kommaet och förbereder och lägger till extra data .
Alternativt med GNU sed
:
sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file
(standard sed
stöder inte kombinationen av 2
och g
som flaggor till s
-kommando).
Kommentarer
- med GNU sed kan du använda
's/,//2g
för att ta bort kommatecken, som börjar med det andra - Och de sista 2 s /// kommandona kan vara
s/.*/|ELEMENT|&|/
men det kan vara mer ansträngning för sed. - @glennjackman Möjligen, men det ser ganska snyggt ut.
- Ja, det här är en del av ett större manus. Matrisen är nödvändig, inte bara för utdata. Därav mitt intresse för parameterbyte. Jag kunde slingra över arrayen med detta men det blir en mardröm att genomföra. Terndon tillhandahöll en loopfri lösning med sed som jag ’ sannolikt kommer att falla tillbaka på om parameterbyte är ett no-go.
- Om jag inte var ’ Det är dock bundet till att använda en array, men det här skulle vara den bästa lösningen.
Svar
ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}"
50,need2
Undvik vanan att använda ALLCAPS-variabelnamn. Du kommer så småningom att kollidera med en viktig ”system” -variabel som PATH och bryta din kod.
Kommentarer
- Inte parameterbyte. MEN jag var inte medveten om att ALLCAPS-variabelnamn var en dålig vana i Bash. Du gör en bra poäng, en som en kortvarig googling definitivt bekräftar. Tack för att du förbättrade min stil! 🙂
- Jag ’ har svarat på frågor där personen skrev
PATH=something; ls $PATH
och undrade sedan omls: command not found
fel. - Det finns nästan hundra inbyggda variabler som är namngivna i alla versaler (klicka igenom den här mansidan länk ) för att se …
Svar
[Detta är i huvudsak ett mer fullt utvecklat version av glenn jackmanns svar ]
Bygga en associerande matris från den avdragna nyckeln och värdet med det första kommaet som 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|
Svar
Du kan slinga över arrayen och använda en mellanliggande variabel:
for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done
Detta tilldelar rest
delen efter det första komma; vi sammanfogar sedan tre delar tillbaka till originalet variabel:
- delen före första komma
- ett komma
- utbyte i
rest
av varje komma med ingenting
Kommentarer
- Det här var min första tanke och är enkelt nog för exemplet men det här är en del av större skript där arrayen är massiv och där ’ redan slingrar och det skulle vara en hel sak. Detta skulle definitivt fungera men skulle vara väldigt besvärligt att genomföra i det större projektet jag ’ arbetar med.
- Rättvis; Jag försökte bara svara inom begränsningarna (endast parameterutvidgning).
RANDOMTEXTTHATWILLNEVERBEINTHEFILE
.