Pomocí substituce parametrů na poli Bash

Mám soubor.txt, který potřebuji přečíst do pole Bash. Pak musím v každém záznamu odstranit mezery, uvozovky a až na první čárku kromě . Jak daleko jsem se dostal:

$ 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| 

Což funguje skvěle, kromě situace s čárkami. Jsem si vědom (a) toho, že existuje několik způsobů, jak tuto kočku skinovat, ale kvůli většímu skriptu, jehož je tato část součástí, bych opravdu rád použil substituci parametrů, abych se sem dostal:

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

Je to možné pomocí substituce parametrů?

Komentáře

  • Existuje nějaký důvod, proč je nutné zachovat text pole a proč ‚ nemůžete nechat např. awk nebo sed zpracovat data?
  • @Jeff – Looping over the array will a a Nightmare to implement in the larger script I ‚ m working on.
  • @JonRed I don ‚ t know what děláte, takže ‚ je zcela možné, že možná nemáte na výběr, ale obecně, když zjistíte, že děláte takovou složitou řetězovou akrobacii v prostředí, že ‚ sa velmi dobře naznačuje, že byste měli používat skutečný programovací jazyk. Shell není navržen jako programovací jazyk, a přestože může být použit jako jeden, není to opravdu dobrý nápad pro složitější věci. ‚ Důrazně vás žádám, abyste zvážili přechod na perl nebo python nebo jakýkoli jiný skriptovací jazyk.
  • @terdon Je to ‚ vtipné, právě jsem řekl téměř přesně to samé kolegovi, než jsem přečetl tento příspěvek. V podstatě jsem řekl, že se jedná o finální verzi tohoto skriptu a že jakékoli další požadavky budou vyžadovat přepisování v Perlu. Takže ano, rozhodně souhlasím

Odpověď

Odstranil bych to, co musíte odstranit pomocí sed před načtením do pole (všimněte si také názvů proměnných s malými písmeny, obecně je nejlepší vyhnout se proměnným s velkými písmeny ve skriptech prostředí):

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

Tím se ve vašem ukázkovém souboru vytvoří následující výstup:

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

Pokud opravdu musíte použít parametr substituce, zkuste něco takového:

#!/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 

Komentáře

  • @JonRed Přidal jsem verzi s parametrem substituce, ale je to ‚ složité, těžkopádné a ošklivé. Dělat takové věci v shellu je velmi zřídka dobrý nápad.
  • Pamatujte, že pokud jste ‚ odstranili mezery i uvozovky, tyto znaky budou k dispozici použít místo vašich RANDOMTEXTTHATWILLNEVERBEINTHEFILE.
  • @Kusalananda jo, právě jsem si přečetl vaši odpověď. To mě mělo napadnout! Díky 🙂
  • Přímo odpovídá na otázku, ilustruje, proč moje preferované řešení není ‚ ideální, a poskytuje nejschodnější alternativu. Vyhrajete, nejlepší odpověď.

Odpověď

Pokud je mi jasné, není třeba přečtěte jej do bash pole a vytvořte tento výstup:

$ 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 výraz vymaže mezery a uvozovky, nahradí první čárku mezerou (v tomto bodě nejsou v řetězci žádné další mezery), vymaže všechny ostatní čárky, obnoví první čárku a doplní a připojí další data .

Alternativně s GNU sed:

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

(standardní sed nepodporuje kombinaci 2 a g jako příznaků s příkaz).

Komentáře

  • s GNU sed, můžete použít 's/,//2g k odstranění čárek, počínaje 2.
  • A poslední 2 s /// příkazy mohou být s/.*/|ELEMENT|&|/ ale to může být pro seda větší úsilí.
  • @glennjackman Možná, ale vypadá to celkem elegantně.
  • Ano, toto je součást většího scénáře. Pole je nezbytné, nejen pro výstup. Proto můj zájem o substituci parametrů. S tím jsem mohl smyčku přes pole, ale implementovat to bude noční můra. Terndon poskytl řešení bez smyčky pomocí sed, na které se ‚ pravděpodobně vrátím, pokud je nahrazení parametrů zakázáno.
  • Kdybych nebyl ‚ s použitím pole, ale toto by bylo nejlepší řešení.

Odpověď

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

Zvykněte si používat názvy proměnných ALLCAPS. Nakonec narazíte na klíčovou „systémovou“ proměnnou, jako je PATH, a rozbijete svůj kód.

Komentáře

  • Není nahrazení parametrů. ALE, nevěděl jsem, že názvy proměnných ALLCAPS jsou v Bashi špatným zvykem. Uděláte dobrý bod, který letmý googling rozhodně potvrdí. Děkuji za zlepšení mého stylu! 🙂
  • Já ‚ zodpovídám otázky, kde daná osoba napsala PATH=something; ls $PATH a pak přemýšlela o ls: command not found chyba.
  • Existuje téměř sto předdefinovaných proměnných, které jsou pojmenovány ve všech velkých písmenech (klikněte na tuto manuálovou stránku odkaz ) vidět …

Odpovědět

[Toto je v podstatě plně rozvinutý verze odpovědi glenna jackmanna ]

Vytváření asociativního pole z odizolovaného klíče a hodnoty pomocí první čárky jako oddělovače:

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| 

Odpověď

Dalo by se smyčka přes pole a použít mezilehlou proměnnou:

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

Tím se rest přiřadí část za první čárkou; poté tři části spojíme zpět do původní proměnná:

  • část před první čárkou
  • čárka
  • náhrada rest každé čárky bez ničeho

komentářů

  • Toto byla moje první myšlenka a je pro příklad dostatečně jednoduchá, ale toto je část většího skriptu, kde je pole masivní a již ‚ s smyčky a byla by to celá věc. To by rozhodně fungovalo, ale bylo by velmi těžkopádné jej implementovat do většího projektu, na kterém pracuji. Pokusil jsem se odpovědět v rámci omezení (pouze rozšíření parametrů).

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *