Chcę usunąć ostatnią kolumnę z pliku txt, a nie wiem jaki jest numer kolumny jest. Jak mogłem to zrobić?
Przykład:
Dane wejściowe:
1223 1234 1323 ... 2222 123 1233 1234 1233 ... 3444 125 0000 5553 3455 ... 2334 222
I chcę, aby mój wynik był :
1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Komentarze
Odpowiedź
Z awk
:
awk "NF{NF-=1};1" <in >out
lub:
awk "NF{NF--};1" <in >out
lub:
awk "NF{--NF};1" <in >out
Chociaż to wygląda jak voodoo, działa. Każde z tych poleceń awk składa się z trzech części.
Pierwsza to NF
, co jest warunkiem wstępnym dla drugiej części. NF
to zmienna zawierająca liczbę pól w linii. W AWK rzeczy są prawdziwe, jeśli „nie są 0 lub pustym ciągiem ""
. Stąd druga część (gdzie NF
jest zmniejszane) ma miejsce tylko wtedy, gdy NF
nie jest równe 0
Druga część (albo NF-=1
NF--
lub --NF
) to po prostu odjęcie jednego ze zmiennej NF
. Zapobiega to wydrukowaniu ostatniego pola, ponieważ kiedy zmienisz pole (w tym przypadku usuniesz ostatnie pole), awk
skonstruujesz ponownie $0
, połącz wszystkie pola domyślnie rozdzielone spacjami . $0
nie „nie zawierało już ostatniego pola.
Ostatnia część to 1
. To nie jest magiczne, jest po prostu używane jako wyrażenie oznaczające true
. Jeśli wyrażenie awk
daje wartość „prawda” bez powiązanego działania, awk
działaniem domyślnym jest print $0
.
Komentarze
- @JJoao: Ach, dzięki, zapomniałem o
--
. Uwaga, obecnie potrzebujesz;1
dla zgodności z POSIX. - Moim początkowym instynktem byłoby użycie pętli for, ale jest to znacznie bardziej zwięzłe i sprytne.
- ' warto zauważyć, że jeśli ' używasz innego niż domyślny separatora, ' Będziemy musieli wprowadzić pewne zmiany. Zakładając, że
,
jest twoim ogranicznikiem:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
- Efektem dekrementacji NF jest niezdefiniowane zachowanie według POSIX – otrzymasz różne wyniki w zależności od tego, który awk ' uruchamiasz. Niektóre awks usuwają ostatnie pole tak, jak chcesz, niektóre nie zrobią nic, a inne mogą zgłosić błąd składni lub cokolwiek innego.
Odpowiedź
Używanie grep
z PCRE:
$ grep -Po ".*(?=\s+[^\s]+$)" file.txt 1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Używanie GNU sed
:
$ sed -r "s/(.*)\s+[^\s]+$/\1/" file.txt 1223 1234 1323 ... 2222 1233 1234 1233 ... 3444 0000 5553 3455 ... 2334
Komentarze
- @ramin Sure. . czy mógłbyś zadać to jako nowe pytanie (tak działa ta strona) 🙂
- @ramin Czy daje jakieś ograniczenie czasowe lub jakieś ostrzeżenie?
- mówi, że to nie jest standardowe pytanie!
- @ramin Ok .. pozwól mi skontaktować się z administratorem, może on może ci w tym pomóc .. przy okazji, czy sprawdziłeś jakąś starą kontrolę jakości dotyczącą twojego pytania? istnieje możliwość, że pytanie zostało już zadane i udzielono na nie odpowiedzi.
- Nie ' nie zadawaj podstawowych pytań, takich jak " jak zmienić nazwę pliku w systemie Linux ". Korzystaj z Google.
Odpowiedz
Za pomocą Perla:
perl -lane "$,=" ";pop(@F);print(@F)" in
Używając rev
+ cut
:
rev in | cut -d " " -f 2- | rev
Odpowiedź
Używanie GNU sed:
sed -r "s/\s+\S+$//" input.txt
Mówiąc bardziej ogólnie, ten działa z sedami BSD w OSX, a także z sedami GNU:
sed "s/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//" input.txt
Odpowiedź
Jeśli separatorem jest zawsze pojedynczy znak (więc dwa lub więcej kolejnych separatorów oznacza puste pola), możesz head
tylko pierwszy wiersz z pliku wejściowego, policzyć ograniczniki ( n
ograniczniki oznacza, że liczba pól wynosi n+1
), a następnie użyj cut
, aby wydrukować z 1
st pole aż do n
pola (przedostatniego), np. z danymi wejściowymi rozdzielanymi znakami tabulacji:
n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l) cut -f1-$n infile > outfile
lub np.z plikiem csv :
n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l) cut -d, -f1-$n infile > outfile
Później przeprowadzę testy porównawcze, jeśli będę miał czas, ale przy dużym wkładzie myślę, że to rozwiązanie powinno być szybsze niż inne rozwiązania, które używają wyrażenia regularnego, ponieważ ten wykonuje minimalne przetwarzanie w pierwszej linii, aby uzyskać liczbę pól, a następnie używa cut
, który jest zoptymalizowany do tego zadania. / p>
Odpowiedź
Przenośnie możesz użyć jednego z poniższych:
sed "s/[[:space:]]*[^[:space:]]*$//" file awk "{sub(/[[:space:]]*[^[:space:]]*$/,"")}1" file
Odpowiedz
Używanie vim:
Otwórz plik w vimie
vim <filename>
Idź do pierwszego wiersza, na wypadek gdyby kursor został umieszczony w innym miejscu.
gg
Utwórz makro o nazwie „q” qq
, który przechodzi na koniec bieżącego wiersza $
, a następnie wraca do ostatniej spacji F
(duże F, po którym następuje dosłowny SPACJA), a następnie usuń od bieżącej pozycji do końca wiersza D
przejdź do następnej linii j
i zatrzymaj nagrywanie makra za pomocą q
.
qq$F Djq
Teraz możemy powtórzyć nasze makro z @q
dla każdego wiersza.
Możemy również nacisnąć @@
aby powtórzyć ostatnie makro lub nawet łatwiej:
99@q
powtórzyć makro 99 razy.
Uwaga: liczba nie może dokładnie odpowiadać wierszom.
Odpowiedź
Dla osób, które mają podobny problem, ale z różnymi separatorami pól, awk
zachowa poprawnie separator pól:
$ cat file foo.bar.baz baz.bar.foo $ awk -F"." "sub(FS $NF,x)" file foo.bar baz.bar
cut
brzmi jak narzędzie do pracy.