Mam w pliku ponad 1000 wierszy. Plik rozpoczyna się w następujący sposób (dodano numery linii):
Station Name
Station Code
A N DEV NAGAR
ACND
ABHAIPUR
AHA
ABOHAR
ABS
ABU ROAD
ABR
Muszę przekonwertować to do pliku z wpisami oddzielonymi przecinkami, łącząc się co dwa wiersze. Ostateczne dane powinny wyglądać
Station Name,Station Code
A N DEV NAGAR,ACND
ABHAIPUR,AHA
ABOHAR,ABS
ABU ROAD,ABR
...
Próbowałem napisać skrypt powłoki, a następnie echo
przecinkiem. Ale wydaje mi się, że prostszy skuteczny liniowiec wykonałby zadanie tutaj, może być w sed
/ awk
.
Jakieś pomysły?
Odpowiedzi:
Po prostu użyj
cat
(jeśli lubisz koty ;-)) ipaste
:Objaśnienie:
paste
odczytuje z wielu plików i wkleja razem odpowiednie linie (linia 1 z pierwszego pliku z linią 1 z drugiego pliku itp.):Zamiast nazwy pliku możemy użyć
-
(myślnik).paste
pobiera pierwszy wiersz z pliku1 (który jest standardem). Następnie chce odczytać pierwszy wiersz z pliku2 (który jest również stdin). Ponieważ jednak pierwszy wiersz stdin został już odczytany i przetworzony, w strumieniu wejściowym czeka teraz druga linia stdin, która zpaste
radością przylega do pierwszego. Ta-d
opcja ustawia separator jako przecinek, a nie tabulator.Możesz też zrobić
PS Tak, można uprościć powyższe do
lub
który ma tę zaletę, że nie używa
cat
.Jednak nie użyłem tego idiomu celowo , ze względu na przejrzystość - jest mniej gadatliwy i lubię
cat
(CATS ARE NICE). Więc proszę nie edytować.Alternatywnie, jeśli wolisz wklejanie niż koty (wklej to polecenie łączenia plików w poziomie, podczas gdy kot łączy je w pionie), możesz użyć:
źródło
paste
Komenda doskonale działa, można proszę dać trochę więcej wyjaśnień na ten temat. Łączniki ???cat
argumentu. Niesed "N;s/\n/,/" file.in > file.out
działa?Jeśli ktoś lądujący tutaj chce połączyć wszystkie linie w jeden liniowiec CSV, spróbuj
źródło
Używając sed, łącz (N) co 2 linie i zamień nowy wiersz (\ n) na „,”.
źródło
Zauważ też, że ponieważ zastępujemy tylko jeden znak innym (każdy nowy wiersz przecinkiem), możemy pracować nad plikiem wejściowym:
(ale uwaga: może nie działać na systemach innych niż Unix, które mają terminatory CRLF (takie jak Microsoft), które niektóre emulowane POSIX
paste
mogą traktować w sposób inny niż Unix)źródło
1
to tutaj robi1<>
? czy to literówka?Oto jedna linijka (choć potencjalnie milion-poleceń-run-er) wykorzystująca czysty Bash:
Używam podpowłoki (nawiasu), aby nie musiałem przechowywać i przywracać
IFS
. Które inaczej należy zrobić, aby nie zepsuć środowiska użytkownika na wypadek, gdyby źródło zostało pozyskane. Alternatywą byłoby przekazanie tego nowego IFS tylkoread
takIFS= read -r name
, jak w ,IFS= read -r code
.Fakt, że wszystkie polecenia w pętli są wbudowane w powłokę, sprawia, że jego wydajność jest akceptowalna i jest nawet szybsza niż inne rozwiązania dla małych plików. Ale wiele osób uważa to za złą praktykę i należy zachować ostrożność przy uogólnianiu tego na cokolwiek innego.
źródło
while IFS='\n' read -r name; do IFS='\n' read -r code ... done < file.in
, co często widzę w skryptach powłoki.-r
Flagi naread
drodze „interpretacji znaku«\», po której następuje znak«n»w strumieniu stdin jako dwóch znaków, a nie jako nową linią.” Być może tworzenie podpowłoki może być bardziej estetyczne niż powtarzanieIFS='\n'
.-r
poprawiono rozwiązanie. Świetny! Nie jestem fanem pomysłuIFS
dwukrotnego przejścia zmienionego . Gdybym użył jednego czytania, bardzo fajnie, ale nie dwa razy. Oczywiście to kwestia opinii . Powiedziałbym, że używanie podpowłoki jest nieco lepsze od ogólnej wiedzy Bash, więc wielu ludzi będzie miało problem ze zrozumieniem jej celu. To zła rzecz.Dla pełnego zestawu odpowiedzi możliwym
awk
rozwiązaniem może być:źródło
printf
? Błąd w rzadkim przypadku, gdy nazwa stacji zawiera specyfikator formatu. (Zobacz przykład pastebin.com/wgxFttrJ .) Ale to tylko przypuszczenie, że opinia nie pochodzi ode mnie.Siwy stary kasztan
awk
idiomuźródło
awk '{ORS=NR%2?",":"\n"};1'
jest krótszy i bardziejprint
że intencja jest jasna.1
jest tak samo jasne dla starychawk
rąk takich jak ja, ale wolęprint
sed
Przed rozpoczęciem poszukiwań walczyłem przez chwilę, aleawk
ułatwiałem łączenie co 4 linie. Uratowała mi podróż do$EDITOR
!Możliwe również z perlem,
perl -pe 's/^\d+\.\s+//;$.&1?chomp:print","' file
źródło
Na przykład:
Wyjście: (uwaga:
xargs -L number_of_columns
działa ładnie z większością dowolnej liczby kolumn, nie tylko co dwie linie)źródło
Rozwiązanie POSIX z
pr
:http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pr.html
źródło