Как заставить команду 'cut' обрабатывать те же последовательные разделители, что и один? - PullRequest
295 голосов
/ 10 ноября 2010

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

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

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

awk '{ printf $4; }'

или sed

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

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

Ответы [ 5 ]

527 голосов
/ 19 декабря 2010

Попробуйте:

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
86 голосов
/ 23 сентября 2014

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

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

tr |cut

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

awk

awk '{print $4}' file

bash

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

sed

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

$ 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

Считывает поля последовательно.Используя _, мы указываем, что это одноразовая переменная как «нежелательная переменная», чтобы игнорировать эти поля.Таким образом, мы сохраняем $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

sed

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

$ sed -r 's/^([^ ]*[ ]*){3}([^ ]*).*/\2/' a
1
2
3
4
24 голосов
/ 03 июля 2014

самое короткое / самое дружелюбное решение

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

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

Один из множества примеров, посвященных этому конкретному вопросу:

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

$ cuts 2 text.txt
2
2

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

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

и многое другое. Ничего из этого не предусмотрено стандартом cut.

Смотри также: https://stackoverflow.com/a/24543231/1296044

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

3 голосов
/ 09 сентября 2015

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

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

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

3 голосов
/ 10 ноября 2010

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

...