har jeg file.txt, som jeg skal læse i et Bash-array. Derefter skal jeg fjerne mellemrum, dobbelt anførselstegn og alt undtagen det første komma i hver post . Her er hvor langt jeg er kommet:
$ 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|
Hvilket fungerer godt bortset fra komma-situationen. Jeg er opmærksom på, at der er flere måder at flå denne kat på, men på grund af det større script, dette er en del af, vil jeg meget gerne bruge parameterudskiftning for at komme hertil:
|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Er dette muligt via parameterudskiftning?
Kommentarer
- Er der nogen grund til at du har brug for at holde teksten inde et array, og hvorfor du ikke kan ‘ t lade f.eks.
awk
ellersed
gør behandlingen af dataene? - @Jeff – Looping over arrayet vil være en mareridt at implementere i det større script jeg ‘ arbejder på.
- @JonRed Jeg ved ikke ‘ ikke hvad du gør, så det er ‘, at du muligvis ikke har et valg i sagen, men generelt, når du finder dig selv i at gøre så komplekse strengakrobatik i skallen, at ‘ er en meget god indikation af, at du skal bruge et faktisk programmeringssprog. Skallen er ikke designet som et programmeringssprog, og selvom den kan bruges som en, er den virkelig ikke ‘ t en god idé til mere komplekse ting. Jeg opfordrer dig kraftigt til at overveje at skifte til perl eller python eller ethvert andet scriptingsprog.
- @terdon Det ‘ er sjovt, jeg er lige færdig med at sige næsten det nøjagtige samme ting til min kollega, før jeg læste dette indlæg. Jeg sagde dybest set, at dette er den endelige version af dette script, og at eventuelle yderligere krav vil kræve omskrivning i Perl. Så ja, jeg er bestemt enig
Svar
Jeg fjerner det, du skal fjerne, ved hjælp af sed
inden indlæsning i arrayet (bemærk også små variabelnavne, generelt er det bedst at undgå kapitaliserede variabler i shell-scripts):
#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done
Dette producerer følgende output på din eksempelfil:
$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Hvis du virkelig skal bruge parameter erstatning, prøv noget som dette:
#!/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
- @JonRed Jeg tilføjede en version med parameter erstatning, men det er ‘ s komplekst, besværligt og grimt. At gøre denne slags ting i skallen er meget sjældent en god idé.
- Bemærk, at hvis du ‘ har fjernet begge mellemrum og dobbelte citater, bliver disse tegn tilgængelige at bruge i stedet for din
RANDOMTEXTTHATWILLNEVERBEINTHEFILE
. - @Kusalananda ja, jeg har lige læst dit svar. Burde have tænkt på det! Tak 🙂
- Svarer direkte på spørgsmålet, illustrerer hvorfor min foretrukne løsning ikke er ‘ t ideel og giver det mest levedygtige alternativ. Du vinder, bedste svar.
Svar
Så vidt jeg kan se, er der ingen grund til læs det ind i et bash
array for at skabe det output:
$ 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
udtryk sletter mellemrum og dobbelt anførselstegn, erstatter det første komma med et mellemrum (der er ingen andre mellemrum i strengen på dette tidspunkt), sletter alle andre kommaer, gendanner det første komma, og forudbetaler og tilføjer de ekstra data .
Alternativt med GNU sed
:
sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file
(standard sed
understøtter ikke kombinationen af 2
og g
som flag til s
kommando).
Kommentarer
Svar
ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}"
50,need2
Bliv vant til at bruge ALLCAPS-variabelnavne. Du kolliderer til sidst med en vigtig “system” -variabel som PATH og bryder din kode.
Kommentarer
- Ikke parametererstatning. MEN jeg var ikke klar over, at ALLCAPS-variabelnavne var en dårlig vane i Bash. Du gør et godt punkt, en som en kortvarig googling bestemt bekræfter. Tak fordi du forbedrede min stil! 🙂
- Jeg ‘ har besvaret spørgsmål, hvor personen skrev
PATH=something; ls $PATH
og derefter undrede sig overls: command not found
fejl. - Der er næsten hundrede indbyggede variabler, der er navngivet i alle bogstaver (klik gennem denne mandside link ) for at se …
Svar
[Dette er i det væsentlige en mere fuldt udviklet version af glenn jackmanns svar ]
Opbygning af et associerende array fra den strippede nøgle og værdi ved hjælp af det første komma 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 løbe over arrayet og bruge en mellemvariabel:
for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done
Dette tildeler rest
delen efter det første komma; vi sammenkæder derefter tre stykker tilbage i originalen variabel:
- delen før det første komma
- et komma
- udskiftning i
rest
af ethvert komma med intet
Kommentarer
- Dette var min første tanke og er enkel nok til eksemplet, men dette er en del af større script, hvor arrayet er massivt, og der ‘ allerede sløjfer, og det ville være en hel ting. Dette ville helt sikkert fungere, men ville være meget besværligt at implementere i det større projekt, jeg ‘ arbejder på.
- Fair nok; Jeg prøvede bare at svare inden for begrænsningerne (kun parameterudvidelse).
's/,//2g
for at fjerne kommaer, startende med 2.s/.*/|ELEMENT|&|/
men det kan være en større indsats for sed.