Как удалить последний столбец файла в Linux

25

Я хочу удалить последний столбец текстового файла, пока я не знаю, что такое номер столбца. Как я мог это сделать?

Пример:

Входные данные:

1223 1234 1323 ... 2222 123
1233 1234 1233 ... 3444 125
0000 5553 3455 ... 2334 222

И я хочу, чтобы мой вывод был:

1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
Зара
источник
Есть много способов сделать это .. пожалуйста, добавьте пример и ожидаемый результат от него ..
Heemayl
@heemayl хорошо, я сделал
Зара
Спасибо .. табуляция столбцов разделена или разделена пробелом?
Heemayl
@heemayl пространство deliminator
Зара

Ответы:

43

С awk:

awk 'NF{NF-=1};1' <in >out

или:

awk 'NF{NF--};1' <in >out

или:

awk 'NF{--NF};1' <in >out

Хотя это выглядит как вуду, это работает. Каждая из этих команд awk состоит из трех частей.

Первый NF, который является предварительным условием для второй части. NFпеременная, содержащая количество полей в строке В AWK все верно, если они не 0 или пустая строка "". Следовательно, вторая часть (где NFуменьшается) происходит только если NFне 0.

Вторая часть (или NF-=1 NF--или --NF) просто вычитает одну из NFпеременной. Это предотвращает печать последнего поля, потому что при изменении поля (в этом случае удаляется последнее поле) awkвоссоздайте $0, объедините все поля, разделенные пробелом по умолчанию. $0больше не было последнего поля.

Заключительная часть есть 1. Это не волшебство, это просто выражение, которое означает true. Если awkвыражение имеет значение true без какого-либо связанного действия, awkдействие по умолчанию равно print $0.

cuonglm
источник
@JJoao: Ах, спасибо, забыл о --. Примечание, в настоящее время вам нужно ;1для POSIX-совместимого.
cuonglm
Мой первоначальный инстинкт должен был бы использовать цикл for, но это намного более кратко и умно.
Сергей Колодяжный
5
Стоит отметить, что если вы используете разделитель не по умолчанию, вам нужно будет внести некоторые изменения. Предположим ,, ваш разделитель:awk -F',' 'BEGIN { OFS = FS }; NF { NF -= 1 }; 1' < in > out
Мистер Лама
1
Эффект уменьшения NF - неопределенное поведение POSIX - вы получите различный вывод в зависимости от того, какой awk вы используете. Некоторые awks удаляют последнее поле по вашему желанию, некоторые вообще ничего не делают, другие могут сообщать о синтаксической ошибке или о чем-то еще.
Эд Мортон
16

Использование grepс PCRE:

$ grep -Po '.*(?=\s+[^\s]+$)' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334

Используя GNU sed:

$ sed -r 's/(.*)\s+[^\s]+$/\1/' file.txt 
1223 1234 1323 ... 2222
1233 1234 1233 ... 3444
0000 5553 3455 ... 2334
heemayl
источник
1
@ramin Конечно .. не могли бы вы задать его как новый вопрос (так работает этот сайт) :)
heemayl
@ramin Дает ли вам какое-либо ограничение по времени или предупреждение?
Heemayl
это говорит, что это вне стандартного вопроса!
Зара
@ramin Хорошо. Позвольте мне связаться с администратором, может быть, они могут помочь вам с этим .. Кстати, вы проверили какой-либо старый QA относительно вашего вопроса?
Вполне
3
Не задавайте супер базовых вопросов, таких как « как я могу переименовать имя файла в Linux ». Используйте Google.
Кристофер Хаммарстрем
11

Использование Perl:

perl -lane '$,=" ";pop(@F);print(@F)' in

Используя rev+ cut:

rev in | cut -d ' ' -f 2- | rev
кос
источник
5

Использование GNU sed:

sed -r 's/\s+\S+$//' input.txt

В более общем смысле, этот работает с BSD sed в OSX, а также с GNU sed:

sed 's/[[:space:]]\{1,\}[^[:space:]]\{1,\}$//' input.txt
Цифровая травма
источник
1

Если в качестве разделителя всегда используется один символ (поэтому два или более последовательных разделителей обозначают пустые поля), вы можете headпросто указать первую строку в вашем входном файле, сосчитать разделители ( nразделители означают количество полей n+1), а затем использовать cutдля печати из 1поля st. до nполя th (от второго до последнего), например, с вводом, разделенным табуляцией:

n=$(head -n 1 infile | tr -dc \\t | tr \\t \\n | wc -l)
cut -f1-$n infile > outfile

или, например, с помощью файла CSV :

n=$(head -n 1 infile | tr -dc , | tr , \\n | wc -l)
cut -d, -f1-$n infile > outfile

Я проведу несколько тестов позже, если у меня будет время, но с огромным вкладом я думаю, что это решение должно быть быстрее, чем другие решения, использующие регулярное выражение, так как это делает минимальную обработку в первой строке, чтобы получить нет. полей, а затем использует cutкоторый оптимизирован для этой работы.

оборота don_crissti
источник
1

Портативно вы можете использовать любой из них:

sed 's/[[:space:]]*[^[:space:]]*$//' file

awk '{sub(/[[:space:]]*[^[:space:]]*$/,"")}1' file
Эд Мортон
источник
0

Используя vim:

Открыть файл в vim

vim <filename> 

Перейти на первый ряд, на всякий случай, если курсор находится в другом месте.

gg

Создайте макрос с именем «q» qq, который идет в конец текущей строки $, затем возвращается к последнему пробелу F(заглавная буква F, затем пробел ), затем удаляется из текущей позиции до конца строки, Dспускается до следующей строки jи остановить запись макроса с помощью q.

qq$F Djq

Теперь мы можем повторить наш макрос с @qкаждой строкой.
Мы также можем нажать, @@чтобы повторить последний макрос или даже проще:

99@q

повторить макрос 99 раз.
Примечание. Число не должно точно соответствовать строкам.

СЕЕ
источник
0

Для людей, имеющих похожую проблему, но с разными разделителями полей, этот awkметод будет правильно сохранять разделитель полей:

$ cat file 
foo.bar.baz
baz.bar.foo
$ awk -F'.' 'sub(FS $NF,x)' file
foo.bar
baz.bar
Htaccess
источник