2010-05-26 11 views
9

Mam plik tekstowy ("input.txt") w formacie:UNIX: Wymień znak nowej linii w/Colon, zachowując znak nowej linii przed EOF

A<LF> 
B<LF> 
C<LF> 
D<LF> 
X<LF> 
Y<LF> 
Z<LF> 
<EOF> 

które muszę sformatować do:

A:B:C:D:X:Y:Z<LF> 
<EOF> 

Wiem, że możesz to zrobić za pomocą "sed". Jest miliard trafień w serwisie Google za pomocą "sed". Ale staram się podkreślać czytelność, prostotę i użycie właściwego narzędzia do prawidłowej pracy. "sed" to edytor linii, który pochłania i ukrywa nowe linie. Prawdopodobnie nie jest to właściwe narzędzie do tej pracy!

Myślę, że właściwym narzędziem do tej pracy będzie "tr". Mogę zastąpić wszystkie nowe linie dwukropkami poleceniem:

cat INPUT.txt | tr '\n' ':' 

Wykonałem 99% mojej pracy. Teraz mam jednak problem. Zamieniając wszystkie nowe linie na dwukropki, nie tylko dostaję obcą postać na końcu sekwencji, ale także tracę powrót karetki na końcu danych wejściowych. Wygląda to tak:

A:B:C:D:X:Y:Z:<EOF> 

Teraz muszę usunąć dwukropek z końca wprowadzania danych. Jeśli jednak spróbuję przekazać przetworzone dane wejściowe przez "sed", aby usunąć końcową okrężnicę (co teraz, jak sądzę, byłoby odpowiednim użyciem "sed"), znajduję się z drugim problemem. Wejście nie jest już w ogóle zakończone znakiem nowej linii! "sed" kończy się niepowodzeniem, dla wszystkich poleceń, ponieważ nigdy nie znajduje końca pierwszej linii danych wejściowych!

Wygląda na to, że dodanie nowego wiersza do końca niektórych danych wejściowych jest bardzo, bardzo częstym zadaniem, i biorąc pod uwagę, że ja sam miałem po prostu ochotę napisać program do wykonania w C (co zajęłoby około ośmiu linii kodu), Nie mogę sobie wyobrazić, że nie ma już prostego sposobu na zrobienie tego przy pomocy narzędzi już dostępnych w jądrze Linuksa.

Odpowiedz

13

To powinno załatwić sprawę (cat i echo są zbędne):

tr '\n' ':' < INPUT.TXT | sed 's/:$/\n/' 

Korzystanie tylko sed:

sed -n ':a; $ ! {N;ba}; s/\n/:/g;p' INPUT.TXT 

Bash bez zewnętrznymi:

string=($(<INPUT.TXT)) 
string=${string[@]/%/:} 
string=${string//: /:} 
string=${string%*:} 

za pomocą pętli w sh:

colon='' 
while read -r line 
do 
    string=$string$colon$line 
    colon=':' 
done < INPUT.TXT 

Korzystanie AWK:

awk '{a=a colon $0; colon=":"} END {print a}' INPUT.TXT 

Lub:

awk '{printf colon $0; colon=":"} END {printf "\n" }' INPUT.TXT 

Edit:

Oto kolejny sposób w czystej Bash:

string=($(<INPUT.TXT)) 
saveIFS=$IFS 
IFS=':' 
newstring="${string[*]}" 
IFS=$saveIFS 

Edit 2:

Oto kolejny sposób, który robi korzystanie echo:

echo "$(tr '\n' ':' < INPUT.TXT | head -c -1)" 
+0

Początkowo byłem zdumiony, dlaczego wysłałeś jako rozwiązanie dokładnie to, co powiedziałem, nie działa, więc spróbowałem go na innej maszynie. Uświadomiłem sobie, że serwer Sun, na którym potrzebowałem rozwiązania, nie używał GNU "sed". Wersja "sed" na serwerze kończy się niepowodzeniem, gdy dane wejściowe nie zawierają kończącej nowej linii, a zatem, jak opisano, dlaczego użyłem "echo". ((Serwer jest urządzeniem o znaczeniu krytycznym w pracy, które nigdy się nie zawiodło, a zatem nigdy nie zostało ponownie uruchomione, nie mówiąc już o aktualizacjach, od lat.) Witam w moim życiu.)) Rozwiązanie z pętli powłoki jest niesamowite, chociaż . – Maarx

+0

/bin/sed na Słońcu ... ick. Co powiecie na/usr/xpg4/bin/sed? –

1

Oto jeszcze inne rozwiązanie: (zakłada zestaw znaków, gdzie ':' jest ósemkowej 72, np. ascii)

 
perl -l72 -pe '$\="\n" if eof' INPUT.TXT 
2

Stare pytanie, ale

paste -sd: INPUT.txt 
Powiązane problemy