2015-07-06 18 views
12

Mam plik parse.txtodwrócić pliku w systemie Unix shell

parse.txt zawiera następujące

remo/hello/1.0,remo/hello2/2.0,remo/hello3/3.0,whitney/hello/1.0,julie/hello/2.0,julie/hello/3.0 

i chcę plik Output.txt jako (aby odwrócić kolejność od ostatnia pierwszy) używając parse.txt

julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0 

próbowałem następujący kod:

tail -r parse.txt 

Odpowiedz

4

Można użyć tej komendy awk:

awk -v RS=, '{a[++i]=$1} END{for (k=i; k>=1; k--) printf a[k] (k>1?RS:ORS)}' parse.txt 
julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0 
26

Możesz użyć zaskakująco pomocnego tac od GNU Coreutils.

tac -s "," parse.txt > newparse.txt 

tac domyślnie będzie „kot” plik na standardowe wyjście, odwracanie linii. Po określeniu separatora za pomocą flagi -s można po prostu odwrócić pola zgodnie z potrzebami.

(Być może trzeba zrobić krok do post-processing, aby uzyskać przecinki działać prawidłowo, co może być kolejnym krokiem w rurociągu.)

+5

Tylko uważaj, że nowa linia będzie częścią ostatniego pola, jeśli istnieje jeden –

+1

DZIĘKUJEMY za zastrzeżenie, że jest to część GNU Coreutils. Ludzie często zapominają, że nie wszyscy używają Linuksa. – ghoti

+0

@EricRenouf - Czy są jakieś obejścia tego problemu? Na przykład, przypuśćmy, że zamiast odwracania pojedynczej linii, OP potrzebuje odwrócić każdą linię w pliku? –

2

Można użyć dowolnego języka to zrobić

xargs ruby -e "puts ARGV[0].split(',').reverse.join(',')" < parse.txt 
+2

Musisz "chomp", a xargs wydaje się niepotrzebnie skomplikowany: 'ruby -ne 'umieszcza $ _. chomp.split (", "). reverse.join (", ")' parse.txt' –

-1

Do odwrotu można użyć tac (z kota). Jak zauważyłem, to odwróci linie, a nie to, o co poprosił PO.

tac filename 

Można nadal jesteś tac jeśli podasz wiersz po wierszu i do tyłu przez nie Linefeed separatora ale separatora pól, tutaj ,.

echo "a,b,c" | tr '\n' ',' | tac -s "," | sed 's/,$/\n/' 
+1

Chodzi o to, aby odwrócić pola w każdej linii, a nie odwrócić linii w pliku. –

+0

@glennjackman Przepraszamy za niepełną odpowiedź. wiersze w plikach są określane przez separator, który jest domyślnie nowy. Zmieniając separator na separator w poście, możesz uzyskać odwrócenie pól. – karakfa

9

podoba mi się rozwiązanie tac; jest ciasno i elegancko, ale jak zauważył Micah, tac jest częścią GNU Coreutils, co oznacza, że ​​nie jest domyślnie dostępny w FreeBSD, OSX, Solaris, itp.

Można to zrobić w czystej bashie, bez narzędzi zewnętrznych wymagany.

#!/usr/bin/env bash 

unset comma 
read foo < parse.txt 
bar=(${foo//,/ }) 
for ((count="${#bar[@]}"; --count >= 0;)); do 
    printf "%s%s" "$comma" "${bar[$count]}" 
    comma="," 
done 

To oczywiście obsługuje tylko jedną linię, na dane wejściowe próbki. Możesz go zawinąć w coś, jeśli potrzebujesz obsługi wielu linii wejścia.

Logika polega na tym, że możemy przekonwertować dane wejściowe na tablicę, zastępując przecinki spacjami. Oczywiście, gdyby nasze dane wejściowe zawierały spacje, należałoby to skorygować. Kiedy już mamy tablicę, przechodzimy do tyłu, drukując każdy rekord.

Należy zauważyć, że nie obejmuje to kończącego znaku nowej linii. Jeśli chcesz, możesz go dodać za pomocą:

printf '\n' 

jako ostatnia linia.

+1

Prostsze, zamień 'printf '\ n'' na' echo' –

+1

Możesz zastąpić linie 'read' i' bar = 'za pomocą' IFS =, przeczytaj -a pasek

+0

@glennjackman, wiesz, ja * wiem * że 'echo' zachowuje się konsekwentnie tak długo, jak długo jesteś w bashu, ale lata temu wydostałem się z nawyku używania go z powodu niespójności w innych powłokach i systemach operacyjnych i od tego czasu utknąłem z 'printf'. Na szczęście zarówno 'echo' i' printf' są wbudowane w bash, więc nie ma poważnego trafienia wydajności. :) – ghoti

7
perl -F, -lane 'print join ",", reverse @F' parse.txt > output.txt 
4

Pytanie oznaczone i wspomnieli tail -r co sugeruje, że nie można używać Linuksa (z toolchain GNU), lecz jakiś „prawdziwy” Unix (wariant BSD), na przykład .

Jako takie, polecenie tac nie jest dostępne, ale jak wspomniano w pytaniu, jest to tail -r. Więc można użyć następujących:

$ tr ',' '\n' < parse.txt | tail -r | tr '\n' ',' | sed 's/,$//' 
julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0 
$ 

Uwagi:

  • Działa to tylko dla plików, które mają jedną linię, jak jesteśmy powołując się na konwersję do nowej linii i plecy przecinków. Jeśli istnieje więcej niż jedna linia, wówczas nowe linie pośrednie zostaną skonwertowane na przecinki do sekundy tr.
  • Końcowy sed jest usunięcie przecinek wzdłużny, który został przekształcony z nową linią tylnej wprowadzona tail
2

Emulacja tac z sed:

tr , '\n' <parse.txt | sed '1!G; h; $!d' | paste -sd , 

Alternatywnie, jeśli nie ma paste :

tr , '\n' <parse.txt | sed '1!G; h; $!d' | tr '\n' , | sed 's/,$//' 

Wyjście:

julie/hello/3.0,julie/hello/2.0,whitney/hello/1.0,remo/hello3/3.0,remo/hello2/2.0,remo/hello/1.0 
Powiązane problemy