Jak analizować dane CSV w Bash

Opublikowany: 2022-09-16
Jane Kelly/Shutterstock.com

Pliki z wartościami oddzielonymi przecinkami (CSV) są jednym z najpopularniejszych formatów eksportowanych danych. W systemie Linux możemy odczytywać pliki CSV za pomocą poleceń Bash. Ale może się to bardzo skomplikować, bardzo szybko. Pomożemy.

Co to jest plik CSV?

Plik wartości oddzielonych przecinkami to plik tekstowy, który zawiera dane tabelaryczne. CSV to rodzaj danych rozdzielanych. Jak sama nazwa wskazuje, przecinek „ , ” służy do oddzielenia każdego pola danych – lub wartości – od jego sąsiadów.

Co to jest plik CSV i jak go otworzyć?
POKREWNE Co to jest plik CSV i jak go otworzyć?

CSV jest wszędzie. Jeśli aplikacja ma funkcje importu i eksportu, prawie zawsze będzie obsługiwać CSV. Pliki CSV są czytelne dla człowieka. Możesz zajrzeć do nich mniej, otwierać je w dowolnym edytorze tekstu i przenosić z programu do programu. Na przykład możesz wyeksportować dane z bazy danych SQLite i otworzyć je w LibreOffice Calc.

Jednak nawet CSV może się skomplikować. Chcesz mieć przecinek w polu danych? To pole musi być otoczone cudzysłowami „ " ”. Aby umieścić cudzysłowy w polu, każdy cudzysłów należy wpisać dwukrotnie.

Oczywiście, jeśli pracujesz z CSV wygenerowanym przez program lub skrypt, który napisałeś, format CSV prawdopodobnie będzie prosty i bezpośredni. Jeśli jesteś zmuszony do pracy z bardziej złożonymi formatami CSV, a Linux jest Linuksem, istnieją rozwiązania, których możemy użyć również do tego celu.

Niektóre przykładowe dane

Możesz łatwo wygenerować przykładowe dane CSV, korzystając z witryn takich jak Generator danych online. Możesz zdefiniować żądane pola i wybrać liczbę wierszy danych. Twoje dane są generowane przy użyciu realistycznych wartości fikcyjnych i pobierane na Twój komputer.

Stworzyliśmy plik zawierający 50 wierszy fikcyjnych informacji o pracownikach:

  • id : Prosta unikalna wartość całkowita.
  • imię : imię osoby.
  • nazwisko : Nazwisko osoby.
  • job-title : Tytuł zawodowy danej osoby.
  • adres e-mail : adres e-mail osoby.
  • oddział : Oddział firmy, w której pracują.
  • state : stan, w którym znajduje się oddział.

Niektóre pliki CSV mają wiersz nagłówka z listą nazw pól. Nasz przykładowy plik ma jeden. Oto początek naszego pliku:

Przykładowy plik CSV

Pierwszy wiersz zawiera nazwy pól jako wartości oddzielone przecinkami.

Parsowanie danych z pliku CSV

Napiszmy skrypt, który odczyta plik CSV i wyodrębni pola z każdego rekordu. Skopiuj ten skrypt do edytora i zapisz go w pliku o nazwie „field.sh”.

 #! /bin/bash

podczas gdy IFS=”, czytaj -r id imię nazwisko stanowisko e-mail stan oddziału
robić
  echo "Identyfikator rekordu: $id"
  echo "Imię: $Imię"
  echo " Nazwisko: $nazwisko"
  echo "Tytuł pracy: $jobtitle"
  echo "Dodaj e-mail: $email"
  echo " Gałąź: $gałąź"
  echo " Stan: $stan"
  Echo ""
gotowe < <(tail -n +2 sample.csv)

W naszym małym skrypcie jest całkiem sporo. Rozbijmy to.

Jak przetwarzać wiersz po wierszu w skrypcie Linux Bash?
POWIĄZANE Jak przetwarzać wiersz po wierszu w skrypcie Linux Bash

Używamy pętli while . Dopóki warunek pętli while zostanie spełniony, while pętli zostanie wykonana. Treść pętli jest dość prosta. Zbiór instrukcji echo jest używany do drukowania wartości niektórych zmiennych w oknie terminala.

Warunek while pętli jest bardziej interesujący niż treść pętli. Określamy, że przecinek powinien być używany jako wewnętrzny separator pól, z instrukcją IFS="," . IFS jest zmienną środowiskową. Polecenie read odnosi się do jego wartości podczas analizowania sekwencji tekstu.

Używamy opcji -r polecenia read (zachowaj ukośniki odwrotne), aby zignorować wszelkie ukośniki odwrotne, które mogą znajdować się w danych. Będą traktowane jak zwykłe postacie.

Tekst analizowany przez polecenie read jest przechowywany w zestawie zmiennych nazwanych po polach CSV. Równie dobrze można je nazwać field1, field1, field2, ... field7 , ale znaczące nazwy ułatwiają życie.

Dane są uzyskiwane jako dane wyjściowe z polecenia tail . Używamy tail , ponieważ pozwala nam to w prosty sposób pominąć linię nagłówka pliku CSV. Opcja -n +2 (numer wiersza) nakazuje tail ​​rozpoczęcie czytania od wiersza numer dwa.

Konstrukcja <(...) nazywana jest substytucją procesu. Powoduje, że Bash akceptuje dane wyjściowe procesu tak, jakby pochodziły z deskryptora pliku. Jest to następnie przekierowywane do pętli while , dostarczając tekst, który przeanalizuje polecenie read .

Uczyń skrypt wykonywalnym za pomocą polecenia chmod . Musisz to zrobić za każdym razem, gdy kopiujesz skrypt z tego artykułu. W każdym przypadku zastąp nazwę odpowiedniego skryptu.

 chmod +x pole.sh 

Tworzenie skryptu wykonywalnego za pomocą chmod

Kiedy uruchamiamy skrypt, rekordy są poprawnie dzielone na ich pola składowe, przy czym każde pole jest przechowywane w innej zmiennej.

 ./pole.sh 

Plik CSV przeanalizowany przez skrypt field.sh.

Każdy rekord jest drukowany jako zestaw pól.

Wybieranie pól

Być może nie chcemy lub nie musimy pobierać każdego pola. Możemy uzyskać wybór pól, włączając polecenie cut .

Ten skrypt nazywa się „select.sh”.

 #!/kosz/bash

podczas gdy IFS="," read -r id nazwa stanowiska pracy stan gałęzi
robić
  echo "Identyfikator rekordu: $id"
  echo "Tytuł pracy: $jobtitle"
  echo " Gałąź: $gałąź"
  echo " Stan: $stan"
  Echo ""
gotowe < <(cut -d "," -f1,4,6,7 sample.csv | ogon -n +2)

Dodaliśmy polecenie cut do klauzuli zastępowania procesu. Używamy opcji -d (ogranicznik), aby powiedzieć cut , aby używał przecinków „ , ” jako ogranicznika. Opcja -f (pole) mówi cut , że potrzebujemy pól jeden, cztery, sześć i siedem. Te cztery pola są wczytywane do czterech zmiennych, które są drukowane w treści pętli while .

Oto, co otrzymujemy, gdy uruchamiamy skrypt.

 ./wybierz.sh 

Parsowanie pliku CSV za pomocą field.sh w celu wyodrębnienia określonego wyboru pól

Dodając polecenie cut , jesteśmy w stanie wybrać pola, które chcemy i zignorować te, których nie mamy.

Na razie w porządku. Ale…

Jeśli plik CSV, z którym masz do czynienia, jest nieskomplikowany, bez przecinków i cudzysłowów w danych pola, to, co omówiliśmy, prawdopodobnie spełni Twoje potrzeby w zakresie analizowania pliku CSV. Aby pokazać problemy, które możemy napotkać, zmodyfikowaliśmy małą próbkę danych, aby wyglądała tak.

 identyfikator, imię, nazwisko, stanowisko, adres e-mail, oddział, stan
1, Rosalyn, Brennan, "Steward, Senior", [email protected], Minneapolis, Maryland
2,Danny,Redden,„Analityk „„Budżet”””,[email protected],Wenecja,Karolina Północna
3, Lexi, Roscoe, farmaceuta, Irlington, Vermont;
  • Rekord jeden zawiera przecinek w polu job-title , więc pole musi być ujęte w cudzysłów.
  • Rekord drugi zawiera słowo ujęte w dwa zestawy cudzysłowów w polu jobs-title .
  • Rekord trzeci nie zawiera danych w polu email-address .

Te dane zostały zapisane jako „sample2.csv”. Zmodyfikuj skrypt „field.sh”, aby wywołać „sample2.csv” i zapisz go jako „field2.sh”.

 #! /bin/bash

podczas gdy IFS=”, czytaj -r id imię nazwisko stanowisko e-mail stan oddziału
robić
  echo "Identyfikator rekordu: $id"
  echo "Imię: $Imię"
  echo " Nazwisko: $nazwisko"
  echo "Tytuł pracy: $jobtitle"
  echo "Dodaj e-mail: $email"
  echo " Gałąź: $gałąź"
  echo " Stan: $stan"
  Echo ""
gotowe < <(ogon -n +2 próbka2.csv)

Kiedy uruchamiamy ten skrypt, widzimy pęknięcia pojawiające się w naszych prostych parserach CSV.

 ./field2.sh 

Uruchamianie pola2.sh

Pierwszy rekord dzieli pole stanowiska pracy na dwa pola, traktując drugą część jako adres e-mail. Każde pole po tym jest przesunięte o jedno miejsce w prawo. Ostatnie pole zawiera zarówno branch , jak i wartości state .

Rekord z polem podzielonym na dwa pola

Drugi rekord zachowuje wszystkie cudzysłowy. Powinna mieć tylko jedną parę cudzysłowów wokół słowa „Budżet”.

Rekord z niewłaściwie potraktowanymi cudzysłowami

Trzeci rekord faktycznie obsługuje brakujące pole tak, jak powinien. Brakuje adresu e-mail, ale wszystko inne jest tak, jak powinno.

Rekord z brakującym polem, które jest obsługiwane poprawnie

Wbrew intuicji, w przypadku prostego formatu danych, bardzo trudno jest napisać solidny parser CSV z ogólnymi przypadkami. Narzędzia takie jak awk pozwolą ci się zbliżyć, ale zawsze zdarzają się przypadki skrajne i wyjątki, które się prześlizgną.

Jak korzystać z polecenia awk w systemie Linux?
POWIĄZANE Jak korzystać z polecenia awk w systemie Linux

Próba napisania niezawodnego parsera CSV prawdopodobnie nie jest najlepszym rozwiązaniem. Alternatywne podejście — zwłaszcza jeśli pracujesz do pewnego rodzaju terminu — wykorzystuje dwie różne strategie.

Jednym z nich jest użycie specjalnie zaprojektowanego narzędzia do manipulowania i wyodrębniania danych. Drugim jest oczyszczenie danych i zastąpienie scenariuszy problemów, takich jak osadzone przecinki i cudzysłowy. Twoje proste parsery Bash mogą następnie poradzić sobie z przyjaznym dla Bash plikiem CSV.

Zestaw narzędzi csvkit

Zestaw narzędzi CSV csvkit to zbiór narzędzi stworzonych specjalnie do pomocy w pracy z plikami CSV. Musisz go zainstalować na swoim komputerze.

Aby zainstalować go na Ubuntu, użyj tego polecenia:

 sudo apt install csvkit 

Instalowanie csvkit na Ubuntu

Aby zainstalować go w Fedorze, musisz wpisać:

 sudo dnf zainstaluj python3-csvkit 

Instalowanie csvkit w Fedorze

Na Manjaro polecenie to:

 sudo pacman -S csvkit 

Instalowanie csvkit na Manjaro

Jeśli przekażemy do niego nazwę pliku CSV, narzędzie csvlook wyświetli tabelę pokazującą zawartość każdego pola. Zawartość pola jest wyświetlana, aby pokazać, co reprezentuje zawartość pola, a nie jak są przechowywane w pliku CSV.

Wypróbujmy csvlook z naszym problematycznym plikiem „sample2.csv”.

 csvlook sample2.csv 

kłopotliwy CSV poprawnie przeanalizowany przez csvlook

Wszystkie pola są poprawnie wyświetlane. To dowodzi, że problemem nie jest plik CSV. Problem polega na tym, że nasze skrypty są zbyt uproszczone, aby poprawnie zinterpretować plik CSV.

Aby wybrać określone kolumny, użyj polecenia csvcut . Opcji -c (kolumna) można używać z nazwami pól lub numerami kolumn, albo z kombinacją obu.

Załóżmy, że musimy wyodrębnić imiona i nazwiska, stanowiska i adresy e-mail z każdego rekordu, ale chcemy, aby kolejność imion była „nazwisko, imię”. Wszystko, co musimy zrobić, to umieścić nazwy pól lub numery w żądanej przez nas kolejności.

Wszystkie te trzy polecenia są równoważne.

 csvcut -c nazwisko, imię, stanowisko, przykładowy adres e-mail2.csv
 csvcut -c nazwisko,imię,4,5 próbka2.csv
 csvcut -c 3,2,4,5 sample2.csv 

Zbieranie pól w preferowanej kolejności za pomocą csvcut

Możemy dodać polecenie csvsort , aby posortować dane wyjściowe według pola. Używamy opcji -c (kolumna), aby określić kolumnę, według której ma odbywać się sortowanie, oraz opcji -r (odwrotnej), aby sortować w kolejności malejącej.

 csvcut -c 3,2,4,5 sample2.csv | csvsort -c 1 -r 

Wybieranie pól i sortowanie według jednej kolumny

Aby upiększyć dane wyjściowe, możemy je przesłać przez csvlook .

 csvcut -c 3,2,4,5 sample2.csv | csvsort -c 1 -r | csvlook 

Używanie csvlook do ładnego drukowania posortowanego wyboru pól

Zgrabnym akcentem jest to, że nawet jeśli rekordy są posortowane, wiersz nagłówka z nazwami pól jest utrzymywany jako pierwszy wiersz. Gdy jesteśmy zadowoleni, że mamy dane w pożądany sposób, możemy usunąć csvlook z łańcucha poleceń i utworzyć nowy plik CSV, przekierowując dane wyjściowe do pliku.

Dodaliśmy więcej danych do „sample2.file”, usunęliśmy polecenie csvsort i utworzyliśmy nowy plik o nazwie „sample3.csv”.

 csvcut -c 3,2,4,5 próbka2.csv > próbka3.csv 

Bezpieczny sposób na oczyszczenie danych CSV

Jeśli otworzysz plik CSV w LibreOffice Calc, każde pole zostanie umieszczone w komórce. Możesz użyć funkcji Znajdź i zamień, aby wyszukać przecinki. Możesz je zastąpić słowem „nic”, aby zniknęły, lub znakiem, który nie wpłynie na parsowanie CSV, np. średnikiem „ ; " na przykład.

Nie zobaczysz cudzysłowów wokół cytowanych pól. Jedyne cudzysłowy, które zobaczysz, to osadzone cudzysłowy w danych pola. Są one pokazane jako pojedyncze cudzysłowy. Znalezienie i zastąpienie ich pojedynczym apostrofem „ ' ” zastąpi podwójne cudzysłowy w pliku CSV.

Korzystanie z funkcji znajdowania i zastępowania programu LibreOffice Calc do zastępowania cudzysłowów apostrofami

Wykonanie wyszukiwania i zamiany w aplikacji takiej jak LibreOffice Calc oznacza, że ​​nie można przypadkowo usunąć żadnego z przecinków separatora pól ani usunąć cudzysłowów wokół cytowanych pól. Zmienisz tylko wartości danych pól.

Zmieniliśmy wszystkie przecinki w polach ze średnikami i wszystkie osadzone cudzysłowy z apostrofami i zapisaliśmy nasze zmiany.

Zmodyfikowany plik CSV

Następnie stworzyliśmy skrypt o nazwie „field3.sh”, który analizuje plik „sample3.csv”.

 #! /bin/bash

podczas gdy IFS=”, czytaj -r nazwisko imię stanowisko e-mail
robić
  echo " Nazwisko: $nazwisko"
  echo "Imię: $Imię"
  echo "Tytuł pracy: $jobtitle"
  echo "Dodaj e-mail: $email"
  Echo ""
gotowe < <(tail -n +2 sample3.csv)

Zobaczmy, co otrzymamy, gdy go uruchomimy.

 ./field3.sh 

Sekcja poprawnie przeanalizowanego pliku CSV

Nasz prosty parser może teraz obsłużyć nasze wcześniej problematyczne rekordy.

Zobaczysz dużo CSV

CSV jest prawdopodobnie najbardziej zbliżony do wspólnego języka dla danych aplikacji. Większość aplikacji obsługujących jakąś formę danych obsługuje importowanie i eksportowanie plików CSV. Wiedza o tym, jak radzić sobie z CSV – w realistyczny i praktyczny sposób – zapewni Ci dobrą pozycję.

POWIĄZANE: 9 przykładów skryptów Bash, które pomogą Ci zacząć w systemie Linux