Как заставить команду 'cut' обрабатывать те же последовательные разделители, что и один?

267

Я пытаюсь извлечь определенное (четвертое) поле из текстового потока, скорректированного по пространству. Я пытаюсь использовать команду cut следующим образом:

cat text.txt | cut -d " " -f 4

К сожалению, cut не обрабатывает несколько пробелов как один разделитель. Я мог бы пропустить через awk

awk '{ printf $4; }'

или sed

sed -E "s/[[:space:]]+/ /g"

чтобы свернуть пробелы, но я хотел бы знать, есть ли способ иметь дело с cut и несколькими разделителями изначально?

Теги:
delimiter
cut

5 ответов

502
Лучший ответ

Пытаться:

tr -s ' ' <text.txt | cut -d ' ' -f4

Со страницы руководства tr:

-s, --squeeze-repeats   replace each input sequence of a repeated character
                        that is listed in SET1 with a single occurrence
                        of that character
  • 0
    ах фантастика! Жаль, что я знал этот трюк давно :)
  • 2
    Удивительный трюк. Большое спасибо!
Показать ещё 4 комментария
76

Как вы комментируете свой вопрос, awk - это действительно путь. Использовать cut можно вместе с tr -s, чтобы сжать пробелы, как показывает kev answer.

Позвольте мне, однако, пройти все возможные комбинации для будущих читателей. Объяснения приведены в разделе "Тест".

tr | вырезать

tr -s ' ' < file | cut -d' ' -f4

AWK

awk '{print $4}' file

bash

while read -r _ _ _ myfield _
do
   echo "forth field: $myfield"
done < file

СЕПГ

sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' file

Испытания

С учетом этого файла, давайте протестировать команды:

$ cat a
this   is    line     1 more text
this      is line    2     more text
this    is line 3     more text
this is   line 4            more    text

tr | вырезать

$ cut -d' ' -f4 a
is
                        # it does not show what we want!


$ tr -s ' ' < a | cut -d' ' -f4
1
2                       # this makes it!
3
4
$

AWK

$ awk '{print $4}' a
1
2
3
4

bash

Это последовательно читает поля. Используя _, мы указываем, что это переменная throwaway как "мусорная переменная", чтобы игнорировать эти поля. Таким образом, мы сохраняем $myfield как 4-е поле в файле, независимо от промежутков между ними.

$ while read -r _ _ _ a _; do echo "4th field: $a"; done < a
4th field: 1
4th field: 2
4th field: 3
4th field: 4

СЕПГ

Это улавливает три группы пробелов и пробелов с ([^ ]*[ ]*){3}. Затем он ловит все, что подходит до места в качестве 4-го поля, и, наконец, печатается с \1.

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
  • 2
    awk не только элегантен и прост, он также включен в VMware ESXi, где tr отсутствует.
  • 2
    @ user121391 еще одна причина использовать awk !
Показать ещё 2 комментария
23

кратчайшее/дружественное решение

После разочарования слишком большим количеством ограничений cut, я написал свою собственную замену, которую я назвал cuts для "разрезания стероидов".

cuts обеспечивает то, что, вероятно, является самым минималистским решением этой и многих других проблем, связанных с вырезанием/вставкой.

Один пример из многих, рассматривающих этот конкретный вопрос:

$ cat text.txt
0   1        2 3
0 1          2   3 4

$ cuts 2 text.txt
2
2

cuts поддерживает:

  • автоматическое обнаружение наиболее распространенных полевых разделителей в файлах (+ возможность переопределения значений по умолчанию)
  • multi- char, mixed- char и регулярные выражения с разделителями
  • извлечение столбцов из нескольких файлов со смешанными разделителями
  • смещение от конца строки (с использованием отрицательных чисел) в дополнение к началу строки
  • автоматическое параллельное вставку столбцов (нет необходимости ссылаться paste отдельно)
  • поддержка переупорядочения полей
  • конфигурационный файл, в котором пользователи могут изменять свои личные настройки
  • большой акцент на удобстве пользователя и минималистике требуемой типизации

и многое другое. Ни один из них не предоставляется стандартным cut.

Смотрите также: https://stackoverflow.com/questions/17644000/how-to-get-second-last-field-from-a-cut-command

Источник и документация (бесплатное программное обеспечение): http://arielf.github.io/cuts/

3

Этот однострочный Perl показывает, насколько тесно Perl связан с awk:

perl -lane 'print $F[3]' text.txt

Однако массив autosplit @F начинается с индекса $F[0], тогда как awk-поля начинаются с $1

2

С версиями cut я знаю, нет, это невозможно. cut в первую очередь полезен для разбора файлов, где разделитель не является пробелом (например, /etc/passwd) и имеет фиксированное количество полей. Два разделителя в строке означают пустое поле, и это тоже относится к пробелу.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню