Paraméter-helyettesítés használata egy Bash tömbön

Van fájl.txt fájlom, amelyet be kell olvasnom egy Bash tömbbe. Ezután el kell távolítanom a szóközöket, a dupla idézőjeleket és az összes vesszőt kivéve az összes vesszőt . Itt van, milyen messzire jutottam:

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

A vesszőhelyzet kivételével ez remekül működik. Tisztában vagyok vele, hogy többféle módon lehet megnyúzni ezt a macskát, de a nagyobb szkript miatt ez része, nagyon szeretnék a paraméterekkel helyettesíteni az idejutást:

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

Lehetséges ez a paramétercsere révén?

Megjegyzések

  • Van valami oka annak, hogy a szöveget bent kell tartani egy tömböt, és miért ‘ nem engedheti meg pl. awk vagy sed végzi az adatok feldolgozását?
  • @Jeff – A tömbhöz való hurkolás a rémálom, amelyet a nagyobb szkriptben megvalósítok, én ‘ m dolgozom.
  • @JonRed nem tudom ‘ csinálsz, tehát ‘ teljesen lehetséges, hogy lehet, hogy nincs választási lehetőséged az ügyben, de általában, amikor olyan összetett húrakrobatikát folytatsz a shellben, hogy ‘ nagyon jól jelzi, hogy egy tényleges programozási nyelvet kell használnia. A shell nem programozási nyelvként van megtervezve, és bár használható egyként, valójában nem ‘ nem jó ötlet bonyolultabb dolgokhoz. Erősen sürgetem, hogy fontolja meg a váltást a perlre vagy a pythonra, vagy bármely más szkript nyelvre.
  • @terdon Ez ‘ s vicces, épp most mondtam el a pontos mondást ugyanezt kollégámnak, mielőtt elolvastam ezt a bejegyzést. Alapvetően azt mondtam, hogy ez a szkript végleges verziója, és hogy minden további követelmény szükségessé teszi a Perl-ben történő újbóli írást. Tehát igen, határozottan egyetértek

Válasz

A sed mielőtt a tömbbe töltődik (vegye figyelembe a kisbetűs változóneveket is, általában a legjobb elkerülni a nagybetűs változókat a shell parancsfájlokban):

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

Ez a következő kimenetet eredményezi a példafájlban:

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

Ha valóban használni kell a paramétert cserével próbálkozzon valami ilyesmivel:

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

Megjegyzések

  • @JonRed Hozzáadtam egy verziót paraméterrel helyettesítés, de ‘ összetett, nehézkes és csúnya. Ilyen dolgok végrehajtása a héjban nagyon ritkán jó ötlet.
  • Ne feledje, hogy ha ‘ eltávolította mind a szóközt, mind a dupla idézőjeleket, ezek a karakterek elérhetővé válnak a RANDOMTEXTTHATWILLNEVERBEINTHEFILE helyett.
  • @Kusalananda igen, most olvastam a válaszod. Erre gondoltak volna! Köszönöm 🙂
  • Közvetlenül megválaszolja a kérdést, szemlélteti, hogy az általam preferált megoldás miért nem ideális, és a legéletképesebb alternatívát kínálja-e. Te nyersz, a legjobb válasz.

Válasz

Amennyire látom, nem kell olvassa el egy bash tömbbe a kimenet létrehozásához:

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

A sed kifejezés törli a szóközöket és a dupla idézőjeleket, az első vesszőt szóközzel helyettesíti (ezen a ponton nincsenek más szóközök a karakterláncban), az összes többi vesszőt törli, az első vesszőt visszaállítja, és az előkészíti és hozzáfűzi az extra adatokat .

Alternatív megoldásként a GNU sed:

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

(standard sed nem támogatja a 2 és g kombinációt a parancs).

Megjegyzések

  • a GNU sed használatával használhatja a 's/,//2g vessző eltávolításához, kezdve a 2.
  • És az utolsó 2 s /// parancs lehet s/.*/|ELEMENT|&|/ de ez nagyobb erőfeszítést jelenthet a sed számára.
  • @glennjackman Esetleg, de meglehetősen ügyesnek tűnik.
  • Igen, ez egy nagyobb szkript része. A tömb szükséges, nem csak a kimenethez. Ezért érdeklődöm a paraméterek helyettesítése iránt. Ezzel át tudnám hurkolni a tömböt, de ezt rémálom lesz megvalósítani. Terndon egy hurok nélküli megoldást nyújtott a sed használatával, amellyel valószínűleg I ‘ visszaesem, ha a paraméter-helyettesítés tilos.
  • Ha nem voltam = “fb841fb5b8”>

nem egy tömb használatához kötött, de ez lenne a legjobb megoldás.

Válasz

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

Lépjen ki az ALLCAPS változónevek használatának szokásából. Végül összeütközik egy olyan fontos “rendszer” változóval, mint a PATH, és megtöri a kódját.

Megjegyzések

  • Nem paramétercsere. DE, nem tudtam, hogy az ALLCAPS változónevek rossz szokás Bash-ban. Ön jó észrevételt tesz, amelyet egy felületes guglizás mindenképpen megerősít. Köszönöm, hogy javítottad a stílusomat! 🙂
  • Én ‘ válaszoltam azokra a kérdésekre, ahol az illető írt PATH=something; ls $PATH, majd kíváncsi voltam a ls: command not found hiba.
  • Közel száz beépített változó van, amelyeket minden nagybetűvel elneveznek (kattintson ezen a man oldalon link ), hogy lássa …

Válasz

[Ez lényegében egy fejlettebb glenn jackmann válaszának változata ]

Asszociatív tömb építése a lecsupaszított kulcsból és értékből, az első vessző elválasztóként történő felhasználásával:

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| 

Válasz

Áthúzhatja a tömböt, és használhat egy köztes változót:

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

Ez hozzárendeli a rest -hez az első vessző utáni részt; ezután három darabot összefűzünk az eredetibe változó:

  • az első vessző előtti rész
  • vessző
  • minden vessző cseréje a rest ben semmivel

Megjegyzések

  • Ez volt az első gondolatom, és elég egyszerű a példához, de ez egy nagyobb szkript része, ahol a tömb masszív és ‘ s már hurkol, és ez egy egész dolog lenne. Ez mindenképpen működne, de nagyon nehézkes lenne megvalósítani a nagyobb projektben, amelyen én ‘ m dolgozom.
  • Elég korrekt; Csak korlátozásokon belül próbáltam válaszolni (csak a paraméterek bővítése).

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük