Как я могу удалить 5-е слово каждой строки в файле?

13

Я хочу удалить 5-е слово каждой строки в файле.

Текущее содержимое файла:

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  

Ожидаемый результат:

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
источник

Ответы:

31

Как насчет 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' ' устанавливает разделитель как пробел

  • -f1-4,6- выбирает поле с первого по четвертое (слово), оставляя 5-е поле, а затем продолжает печатать с 6-го до остальных.

heemayl
источник
11

Решение с cut:

cut -d ' ' -f1-4 -f6- FILE
fd0
источник
Множественный -fне поддерживается в моем cut(GNU) по крайней мере ..
Heemayl
Поддерживается в BSD Cut, но мне нравится ваш ответ лучше, чем мой.
fd0
1
Если это GNU вырезать, вы получите --complementфлаг , чтобы упростить вещи: cut --complement -d ' ' -f5. Не забудьте перенаправить вывод в новый файл, а затем mvповерх оригинала.
Тоби Спейт
6

awk: убрать 5-е поле

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

Если вы хотите сохранить файл на месте: /programming//q/16529716/7552

Вы можете просто стереть содержимое 5-го поля, но это оставляет 2 последовательных разделителя выходных полей:

awk '{$5 = ""};1' file
Гленн Джекман
источник
оговорка здесь заключается в том, что изменение значения любого поля в awk имеет побочный эффект - перезаписывает весь «$ 0» только с одним разделителем между каждым полем. следует принять во внимание, если вы хотите сохранить какое-либо выравнивание (если у gnu awk нет возможности избежать этого? обычный awk / nawk будет пересчитывать $ 0)
Оливье Дюлак
В обоих случаях вы переформатируете строку с одним разделителем. Если в разделителе есть 2 пробела или пробел + табуляция, результатом будет один пробел на месте. Надеюсь, это нормально для большей части текста.
NeronLeVelu
4

С помощью POSIX sed:

sed -e 's/[^[:alnum:]_][[:alnum:]_][[:alnum:]_]*//4' <file
cuonglm
источник
зачем ограничивать класс: alnum: _ а не чем-то еще :blank:или :space:?
NeronLeVelu
@NeronLeVelu: Это зависит от того, как вы определяете, что делают слово.
Cuonglm
@mikeserv; Хорошо поймал! Я обновил свой ответ.
cuonglm
Для чего \(нужна группа захвата \)?
mikeserv
@mikeserv: моя ошибка ввода, я только что попробовал несколько способов сохранить разделитель.
cuonglm
2

Гленн предложил решение, которое эквивалентно

awk '{$ 5 = ""; печать} ' файл

Как он и другие указали, это

  1. убирает начальные и конечные пробелы из каждой строки,
  2. сжимает каждую строку пробелов (пробелы и / или табуляции) в один пробел, и
  3. оставляет два пробела между четвертым и шестью словами.

Взломать, чтобы исправить третью проблему

awk '{$ 5 = ""; печать} ' файл | sed 's / / /'

Это по-прежнему оставит один или несколько добавленных пробелов в конце любой строки, в которой вводится пять или менее слов. Если вы можете определить слово, которое никогда не появится на входе,

awk '{$ 5 = "единорог"; печать} ' файл | sed 's / * единорог //'

справится даже с этим (но это все равно оставляет проблемы 1 и 2).

Скотт
источник
2
 sed 's/^\(\([[:blank:]]*[^[:blank:]]\{1,\}\)\{4\}\)[[:blank:]]*[^[:blank:]]*/\1/' YourFile > Output.txt
  • posix sed на основе разделителя пробела / табуляции (метакласс [: blank:]])
  • оставьте следующий пробел после 5-го слова, но удалите предыдущий

Более надежный (sed принимает самый длинный шаблон и шаблон с *пропущенным разделением или словом в первой версии), но более длинная версия

sed 's/^\([[:blank:]]*\([^[:blank:]]\{1,\}[[:blank:]]\{1,\}\)\{4\}\[^[:blank:]]\{1,\}/\1/' YourFile > Output.txt
NeronLeVelu
источник
1
sed 's/[^[:blank:]]*//5'
mikeserv
@mikeserv, это будет держать оба окружающих сепаратора, sed 's/[[:blank:]*[^[:blank:]]*//5'лучше. Очень хороший момент. Я подозревал, что sed воспринимает каждый символ как единое целое, но в качестве сущности он принимает наибольший неразбитый шаблон
NeronLeVelu
sed 's/[[:blank:]][^[:blank:]]*//4'удалит 5-е поле целиком.
mikeserv
@mikeserv Предполагая, что на линии нет начального пробела (как в примере)
NeronLeVelu
В этом случае да, я думаю, что вы правы. Обычно такая вещь была бы нулевым полем, и поведение было бы правильным. В этом случае вы должны сделать , как @cuonglm сделал , и убедитесь , что вы ссылаетесь на слово каждый раз , как sed 's/[[:blank:]][^[:blank:]][^[:blank:]]*//4', или, ж / GNU / BSD / Игрушечные seds: sed -E 's/[[:blank:]][^[:blank:]]+//4'.
mikeserv
1

Perl.

perl -ne 'print $_ =~ /^(\w+ +\w+ +\w+ +\w+ +)\w+ (.*)/,"\n"' file
Стив
источник
1

Другая возможность, предполагая, что GNU вырезать:

cut -d' ' -f5 --complement file.txt
Цифровая травма
источник
-1

Используя Perl> 5.10 (и успешно вывести все строки: 0)): -

perl -nE '/^((\w+ +){4})\w+ *(.*)/; say $1.$3' file
Медлок Перлман
источник