[+] doklejanie tekstu do ko

Potrzebujesz pomocy z C, C++, perl, python, itp.
Skibbi
Posty: 33
Rejestracja: 20 lipca 2007, 19:01

[+] doklejanie tekstu do końca pliku - bash

Post autor: Skibbi »

Witam,
Mam do obrobienia kilka plików csv (100-200MB każdy). Muszę przeprowadzić na nich kilka różnych operacji. Utknąłem w jednym punkcie niestety, więc liczę na pomoc bardziej zaawansowanych użytkowników konsoli. Pliki csv zawierają n kolumn, jedna z nich jest w postaci:

Kod: Zaznacz cały

ABC_DE_1234567890_1_1234
Kolumna ta znajduje się na początku, a ja bym chciał wartość z tej kolumny dokleić na koniec pliku:

Kod: Zaznacz cały

kol_A,kol_B,MOJA_KOLUMNA,kol_C,kol_D,MOJA_KOLUMNA_KOPIA
Da się to jakoś zrobić? Póki co mi się udało tę kolumnę odseparować za pomocą regexpa do oddzielnego pliku, ale jak poszczególne linie z tego pliku dokleić do mojego csv?
Awatar użytkownika
lessmian2
Member
Posty: 1088
Rejestracja: 30 kwietnia 2008, 19:38
Lokalizacja: Kraków

Post autor: lessmian2 »

Sprecyzuj. Chodzi Ci o koniec pliku czy linii? Wytrwale piszesz o końcu pliku, a z przykładu wychodzi, że chcesz coś dołożyć na końcu każdej linii z pliku.

Kod: Zaznacz cały

sed -i 's/\(.*,.*\)\(,.*\)\(,.*,.*\)/\1\2\3\2/' plik.csv
To powyżej zrobi coś takiego z każdą linią w pliku:

Kod: Zaznacz cały

# echo 'kol_A,kol_B,MOJA_KOLUMNA,kol_C,kol_D' | sed 's/\(.*,.*\)\(,.*\)\(,.*,.*\)/\1\2\3\2/'
kol_A,kol_B,MOJA_KOLUMNA,kol_C,kol_D,MOJA_KOLUMNA
Skibbi
Posty: 33
Rejestracja: 20 lipca 2007, 19:01

Post autor: Skibbi »

Tak, rzeczywiście chodziło mi o koniec linii w pliku. Kombinowałem z sedem, ale właśnie brakuje kropki nad i. Z tym, że ja kolumn w pliku mam ponad 100, więc ten sed chyba odpada :(
Awatar użytkownika
lessmian2
Member
Posty: 1088
Rejestracja: 30 kwietnia 2008, 19:38
Lokalizacja: Kraków

Post autor: lessmian2 »

E tam. Wszystko się da. Wklej przykładową linię i coś wymyślimy :)
Skibbi
Posty: 33
Rejestracja: 20 lipca 2007, 19:01

Post autor: Skibbi »

Za dużo kolumn by się bawić w kopiuj/wklej. Ale postaram się dać dokładny przykład. Mój plik źródłowy:

Kod: Zaznacz cały

ABC,23-DEF,,45A,<dużo innych kolumn>,[B]ABC_DE_1234567890_1_1234[/B],<dużo innych kolumn>,123ABC,DEFG
ABC,233-AAD,XXDS3984039,45BBGA,<dużo innych kolumn>,[B]XYZ_DE_1234567890_0_6666[/B],<dużo innych kolumn>,3ABC,DEF
Co bym chciał uzyskać:

Kod: Zaznacz cały

ABC,23-DEF,,45A,<dużo innych kolumn>,[B]ABC_DE_1234567890_1_1234[/B],<dużo innych kolumn>,123ABC,DEFG,[color=red][B]ABC_DE_1234567890_1_1234[/B][/color]
 ABC,233-AAD,XXDS3984039,45BBGA,<dużo innych kolumn>,[B]XYZ_DE_1234567890_0_6666[/B],<dużo innych kolumn>,3ABC,DEF,[color=red][B]XYZ_DE_1234567890_0_6666[/B][/color]
Jak widać występują tutaj dwa problemy: kolumna, która mnie interesuje jest w środku (a tych kolumn jest ponad 100 i ich liczba jest różna w zależności od pliku csv) oraz długość wierszy w pliku jest zmienna, czasami kolumna jest pusta więc są dwa przecinki itp.
Awatar użytkownika
lessmian2
Member
Posty: 1088
Rejestracja: 30 kwietnia 2008, 19:38
Lokalizacja: Kraków

Post autor: lessmian2 »

Sprawdź coś takiego:

Kod: Zaznacz cały

# echo 'kol_A,kol_B,MOJA_KOLUMNA,kol_C,kol_D' | perl -lne 'chomp;split",";print join(",",(@_,$_[2]))'
kol_A,kol_B,MOJA_KOLUMNA,kol_C,kol_D,MOJA_KOLUMNA

Kod: Zaznacz cały

perl -i -lne 'chomp;split",";print join(",",(@_,$_[2]))' plik.csv
W $_[2] wstawiasz numer kolumny, liczony od zera.
Awatar użytkownika
turox
Posty: 49
Rejestracja: 19 września 2010, 15:40
Lokalizacja: Tychy

Post autor: turox »

Korzystając z samego tylko basha:

Kod: Zaznacz cały

#!/bin/bash

while read ln ; do
IFS=','
declare -a linia=($ln)
echo -ne "${linia
[*]},${linia[2]}\n"
done < plik.csv
Dokleja na końcu każdej linii zawartość trzeciej kolumny.
Skibbi
Posty: 33
Rejestracja: 20 lipca 2007, 19:01

Post autor: Skibbi »

Dziękuję za basha, zadziałał perfekcyjnie. Co prawda musiałem policzyć która to kolumna musi być doklejona na końcu (wyszło że 186 :P), ale się udało.
A tak się zastanawiam: da się jakoś z pliku wejściowego zrobić dwa pliki wyjściowe w tej pętli? Plik A = oryginalny plik + doklejona kolumna. Plik B = kolumna 1, kolumna 4, kolumna 6. Ale to tak już poza konkursem :)
Jeszcze raz dziękuję za pomoc!
Awatar użytkownika
turox
Posty: 49
Rejestracja: 19 września 2010, 15:40
Lokalizacja: Tychy

Post autor: turox »

Przecież to banał

Kod: Zaznacz cały

#!/bin/bash

IFS=','
> plikA.csv
> plikB.csv

while read ln ; do
  declare -a linia=($ln)
  echo "${linia
[*]},${linia[2]}" >> plikA.csv
  echo "${linia[0]},${linia[3]},${linia[5]}" >> plikB.csv
done < plik.csv
Awatar użytkownika
lessmian2
Member
Posty: 1088
Rejestracja: 30 kwietnia 2008, 19:38
Lokalizacja: Kraków

Post autor: lessmian2 »

Tak w ramach OT. Nie rozumiem czemu tak się boicie tego perla. Zamiast skorzystać z ładnego i krótkiego jednolinijkowca, rozdmuchujecie problem do całkiem sporego, w porównaniu do tego samego kodu w perlu, skryptu w bashu ;) Wszak perl został stworzony do przetwarzania tekstów (choć zastosowań ma o wiele więcej), więc używajmy go, nie gryzie ;)
ODPOWIEDZ