Jak mogę usunąć 5. słowo każdego wiersza w pliku?

13

Chcę usunąć 5. słowo każdego wiersza w pliku.

Obecna zawartość pliku:

File is not updated or and will be removed  
System will shut down f within 10 seconds  
Please save your work 55 or copy to other location  
Kindly cooperate with us D  

Oczekiwany wynik:

File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
pmaipmui
źródło

Odpowiedzi:

31

Co powiesz na cut:

$ cut -d' ' -f1-4,6- file.txt 
File is not updated and will be removed  
System will shut down within 10 seconds  
Please save your work or copy to other location  
Kindly cooperate with us
  • -d' ' ustawia separator jako spację

  • -f1-4,6- wybiera od pierwszego do czwartego pola (słowa), pozostawiając 5., a następnie kontynuuje drukowanie od 6. do reszty.

heemayl
źródło
11

Rozwiązanie z cut:

cut -d ' ' -f1-4 -f6- FILE
fd0
źródło
Wiele -fnie jest obsługiwane w moim cut(GNU) przynajmniej ..
heemayl
Obsługiwane w skrócie BSD, ale bardziej podoba mi się twoja odpowiedź niż moja.
fd0
1
Jeśli jest to GNU cięcie, masz --complementflagę uproszczenia rzeczy: cut --complement -d ' ' -f5. Pamiętaj, aby przekierować wyjście do nowego pliku, a następnie mvna oryginał.
Toby Speight
6

awk: usuwa 5. pole

awk '{for (i=5; i<NF; i++) $i = $(i+1); NF--};1' file

Jeśli chcesz zapisać plik w miejscu: /programming//q/16529716/7552

Możesz po prostu usunąć zawartość 5. pola, ale pozostawia to dwa kolejne separatory pól wyjściowych:

awk '{$5 = ""};1' file
Glenn Jackman
źródło
zastrzeżeniem jest to, że zmiana wartości dowolnego pola w awk powoduje efekt uboczny przepisania całego „0 $” z tylko 1 separatorem między każdym polem. należy wziąć pod uwagę, jeśli chcesz zachować jakiekolwiek wyrównanie (chyba że gnu awk ma opcję uniknięcia tego? zwykły awk / nawk ponownie obliczy 0 USD)
Olivier Dulac
W obu przypadkach ponownie sformatujesz linię za pomocą jednego separatora. Jeśli w separatorze są 2 spacje lub spacja + tab, wynikiem jest pojedyncza spacja na miejscu. Mam nadzieję, że jest to OK dla większości tekstu.
NeronLeVelu,
4

Z POSIX sed:

sed -e 's/[^[:alnum:]_][[:alnum:]_][[:alnum:]_]*//4' <file
Cuonglm
źródło
po co ograniczać klasę do: alnum: _ a nie niczego innego wtedy :blank:lub :space:?
NeronLeVelu,
@NeronLeVelu: To zależy od tego, jak zdefiniujesz, co tworzy słowo.
cuonglm,
@mikeserv; Dobry chwyt! Zaktualizowałem swoją odpowiedź.
cuonglm
Do czego \(służy grupa przechwytywania \)?
mikeserv
@mikeserv: moje błędne pisanie, właśnie wypróbowałem kilka sposobów na zachowanie ogranicznika.
cuonglm
2

glenn zaproponował rozwiązanie równoważne

awk '{$ 5 = ""; print}” plik

Jak zauważył on i inni

  1. usuwa wiodące i końcowe białe spacje z każdej linii,
  2. kompresuje każdy ciąg białych znaków (spacje i / lub tabulatory) w jedną spację, oraz
  3. pozostawia dwie spacje między czwartym a sześcioma słowami.

Hack, aby rozwiązać trzeci problem, to

awk '{$ 5 = ""; print} ' plik | sed 's / / /'

To pozostawi jedno lub więcej dodanych spacji na końcu każdego wiersza, w którym było pięć lub mniej słów. Jeśli potrafisz zidentyfikować słowo, które nigdy nie pojawi się na wejściu,

awk '{5 $ = "jednorożec"; print} ' plik | sed 's / * jednorożec //'

poradzi sobie nawet z tym (ale nadal pozostawia problemy 1 i 2).

Scott
źródło
2
 sed 's/^\(\([[:blank:]]*[^[:blank:]]\{1,\}\)\{4\}\)[[:blank:]]*[^[:blank:]]*/\1/' YourFile > Output.txt
  • posix sed na podstawie separatora spacji / tabulatorów (meta class [: blank:]])
  • zachowaj następującą spację po 5. słowie, ale usuwając poprzednią

Bardziej wytrzymały (sed bierze najdłuższy możliwy wzorzec i wzorzec z *może pomijać separację lub słowo w pierwszej wersji), ale nieco dłuższą wersję

sed 's/^\([[:blank:]]*\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{4\}\[^[:blank:]]\{1,\}/\1/' YourFile > Output.txt
NeronLeVelu
źródło
1
sed 's/[^[:blank:]]*//5'
mikeserv
@ Mikeserv, to pozwoli zachować oba otaczające separatory, sed 's/[[:blank:]*[^[:blank:]]*//5'jest lepiej. Bardzo dobra uwaga. Podejrzewałem, że sed bierze każdy pojedynczy znak jako byt, ale ma największy niezakłócony wzór jako byt
NeronLeVelu
sed 's/[[:blank:]][^[:blank:]]*//4'całkowicie usunie 5. pole.
mikeserv
@mikeserv Zakładając, że na linii nie ma początkowego miejsca (jak w próbce)
NeronLeVelu
W tym przypadku tak, myślę, że masz rację. Zwykle coś takiego byłoby polem zerowym i zachowanie byłoby prawidłowe. W tym przypadku należy zrobić jak @cuonglm zrobił i zapewnić odwołać słowo za każdym razem jak sed 's/[[:blank:]][^[:blank:]][^[:blank:]]*//4', albo w / GNU / BSD / toybox seds: sed -E 's/[[:blank:]][^[:blank:]]+//4'.
mikeserv
1

Perl

perl -ne 'print $_ =~ /^(\w+ +\w+ +\w+ +\w+ +)\w+ (.*)/,"\n"' file
Steve
źródło
1

Inna możliwość, przy założeniu cięcia GNU:

cut -d' ' -f5 --complement file.txt
Cyfrowa trauma
źródło
-1

Używając Perla> 5.10 (i z powodzeniem wypisując wszystkie linie: 0)): -

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file
Medlock Perlman
źródło