Mam plik file.txt, który muszę wczytać do tablicy Bash. Następnie muszę usunąć spacje, podwójne cudzysłowy i wszystkie oprócz pierwszego przecinka w każdym wpisie . Oto „jak daleko” dotarłem:
$ 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 działa świetnie z wyjątkiem sytuacji z przecinkami. Zdaję sobie sprawę, że istnieje wiele sposobów skórowania tego kota, ale ze względu na większy skrypt, którego jest częścią, naprawdę chciałbym użyć zastępowania parametrów, aby dostać się tutaj:
|ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Czy jest to możliwe poprzez podstawianie parametrów?
Komentarze
- Czy jest jakiś powód, dla którego powinieneś zachować tekst w tablicę i dlaczego nie możesz ' np.
awk
lubsed
czy przetwarzane są dane? - @Jeff – pętla po tablicy będzie koszmar do zaimplementowania w większym skrypcie, nad którym pracuję '.
- @JonRed Nie ' nie wiem nad czym co robisz, więc ' jest całkowicie możliwe, że możesz nie mieć wyboru w tej sprawie, ale generalnie, gdy wykonujesz tak złożone akrobacje ze strunami w powłoce, ' to bardzo dobra wskazówka, że powinieneś używać rzeczywistego języka programowania. Powłoka nie została zaprojektowana jako język programowania i chociaż może być używana jako jeden, to naprawdę nie jest ' dobrym pomysłem na bardziej złożone rzeczy. Gorąco zachęcam do rozważenia przejścia na perl, python lub inny język skryptowy.
- @terdon To ' to zabawne, właśnie skończyłem mówić prawie dokładnie to samo do mojego kolegi, zanim przeczytam ten post. Zasadniczo powiedziałem, że jest to ostateczna wersja tego skryptu i że wszelkie dalsze wymagania będą wymagały ponownego napisania w Perlu. Więc tak, zdecydowanie się zgadzam
Odpowiedź
Usunąłbym to, co musisz usunąć, używając sed
przed załadowaniem do tablicy (zwróć także uwagę na nazwy zmiennych z małych liter, generalnie najlepiej jest unikać zmiennych pisanych wielkimi literami w skryptach powłoki):
#!/bin/bash readarray -t array< <(sed "s/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/" "$1") for element in "${array[@]}";do echo "|ELEMENT|$element|" done
Daje to następujące wyniki w pliku przykładowym:
$ foo.sh file |ELEMENT|10,this| |ELEMENT|20,is| |ELEMENT|30,all| |ELEMENT|40,I| |ELEMENT|50,need2| |ELEMENT|60,see|
Jeśli naprawdę musisz użyć parametru podstawienie, spróbuj coś takiego:
#!/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
Komentarze
Odpowiedź
O ile widzę, nie ma potrzeby wczytaj go do tablicy bash
, aby utworzyć wynik:
$ 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
wyrażenie usuwa spacje i podwójne cudzysłowy, zastępuje pierwszy przecinek spacją (w tym miejscu nie ma innych spacji w ciągu), usuwa wszystkie pozostałe przecinki, przywraca pierwszy przecinek, a poprzedza i dołącza dodatkowe dane .
Alternatywnie, z GNU sed
:
sed "s/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/" <file
(standard nie obsługuje kombinacji 2
i g
jako flag do s
polecenie).
Komentarze
- W przypadku GNU sed można użyć
's/,//2g
aby usunąć przecinki, zaczynając od drugiego - Ostatnie 2 s /// polecenia mogą być
s/.*/|ELEMENT|&|/
ale to może być bardziej wymagające dla seda. - @glennjackman Możliwe, ale wygląda raczej zgrabnie.
- Tak, to jest część większego skryptu. Tablica jest niezbędna nie tylko dla danych wyjściowych. Stąd moje zainteresowanie substytucją parametrów. Mógłbym za pomocą tego zapętlić tablicę, ale będzie to koszmar do wdrożenia. Terndon dostarczył rozwiązanie wolne od pętli, używając seda, które ' prawdopodobnie powróci, jeśli podstawianie parametrów okaże się niemożliwe.
- Jeśli nie ' związany z użyciem tablicy, jednak byłoby to najlepsze rozwiązanie.
Odpowiedź
ELEMENT="50,n,e,e,d,2" IFS=, read -r first rest <<<"$ELEMENT" printf "%s,%s\n" "$first" "${rest//,/}"
50,need2
Pozbądź się nawyku używania nazw zmiennych ALLCAPS. W końcu zderzysz się z kluczową zmienną „systemową”, taką jak PATH, i zepsujesz swój kod.
Komentarze
- Brak zastępowania parametrów. ALE, nie byłem świadomy tego, że nazwy zmiennych ALLCAPS były złym nawykiem w Bash. Masz rację, którą pobieżne wyszukiwanie w Google zdecydowanie potwierdza. Dziękuję za ulepszenie mojego stylu! 🙂
- Odpowiedziałem ' na pytania, w których dana osoba napisała
PATH=something; ls $PATH
, a potem zastanawiała się nadls: command not found
. - Istnieje prawie sto wbudowanych zmiennych, które mają nazwy wielkimi literami (kliknij tę stronę podręcznika link ), aby zobaczyć …
Odpowiedź
[Jest to zasadniczo bardziej rozbudowana wersja odpowiedzi glenn jackmann „]
Tworzenie tablicy asocjacyjnej na podstawie usuniętego klucza i wartości, używając pierwszego przecinka jako separatora:
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|
Odpowiedź
Możesz zapętlić tablicę i użyć zmiennej pośredniej:
for((i=0; i < "${#ARRAY[@]}"; i++)) do rest="${ARRAY[i]#*,}" ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}" done
Przypisuje to rest
część po pierwszym przecinku; następnie łączymy trzy części z powrotem w oryginał zmienna:
- część przed pierwszym przecinkiem
- przecinek
- zamiana w
rest
każdego przecinka bez niczego
Komentarze
- To była moja pierwsza myśl i jest wystarczająco prosta dla przykładu, ale jest to część większego skryptu, w którym tablica jest ogromna, a ' już się zapętla i to by była cała rzecz. To z pewnością zadziałałoby, ale byłoby bardzo kłopotliwe we wdrożeniu w większym projekcie, nad którym ' pracuję.
- W porządku; Po prostu próbowałem odpowiedzieć w ramach ograniczeń (tylko rozszerzenie parametrów).
RANDOMTEXTTHATWILLNEVERBEINTHEFILE
.