Bash
Команда cut
Поиск…
Вступление
Команда cut
- это быстрый способ извлечения частей строк текстовых файлов. Он относится к самым старым командам Unix. Его наиболее популярными реализациями является версия GNU, найденная в Linux, и версия FreeBSD, найденная на MacOS, но каждый аромат Unix имеет свои собственные. См. Ниже различия. Строки ввода считываются либо из stdin
либо из файлов, перечисленных в качестве аргументов в командной строке.
Синтаксис
cut -f1,3 # извлечь первое и третье поля с разделителями табуляции (из stdin)
cut -f1-3 # экстракт от первого до третьего поля (в конце включены)
cut -f-3 # -3 интерпретируется как 1-3
cut -f2- # 2- интерпретируется как от второго до последнего
cut -c1-5,10 # extract from stdin символы в позициях 1,2,3,4,5,10
cut -s -f1 # подавлять строки, не содержащие разделителей
cut --complement -f3 # (только разрезание GNU) извлекает все поля, кроме третьего
параметры
параметр | подробности |
---|---|
-f, --fields | Выбор на местах |
-d, --delimiter | Разделитель для выбора на местах |
-c, --characters | Выбор на основе символов, игнорируемый разделитель или ошибка |
-s, - только разграниченные | Удерживать строки без разделительных символов (напечатано как - иначе) |
--complement | Перевернутый выбор (извлекать все, кроме указанных полей / символов |
--output-разделитель | Укажите, когда он должен отличаться от входного разделителя |
замечания
1. Синтаксические различия
Длинные параметры в приведенной выше таблице поддерживаются только версией GNU.
2. Персонаж не получает специального лечения
Например, FreeBSD cut
(который поставляется с MacOS) не имеет ключа --complement
, а в случае диапазонов colrm
вместо него можно использовать команду colrm
:
$ cut --complement -c3-5 <<<"123456789"
126789
$ colrm 3 5 <<<"123456789"
126789
Однако существует большая разница, поскольку colrm
обрабатывает символы TAB (ASCII 9) как реальные таблицы до следующего кратного восьми, а обратные пространства (ASCII 8) равны -1; напротив, cut
обрабатывает всех персонажей как одну ширину столбца.
$ colrm 3 8 <<<$'12\tABCDEF' # Input string has an embedded TAB
12ABCDEF
$ cut --complement -c3-8 <<<$'12\tABCDEF'
12F
3. (Все еще нет) Интернационализация
Когда был разработан cut
, все символы были одним байтом, а интернационализация не была проблемой. При написании систем с более широкими символами стало популярным решение, принятое POSIX, заключалось в том, чтобы подгонять между старым ключом -c
, который должен сохранять смысл выбора символов, независимо от того, сколько байтов в ширину, и ввести новый переключатель -b
который должен выберите байты, независимо от текущей кодировки символов. В большинстве популярных реализаций -b
был введен и работает, но -c
все еще работает точно так же, как -b
но не так, как должно. Например, при cut
GNU:
Кажется, что спам-фильтр SE черным списком английских текстов с изолированными иероглифами кандзи в них. Я не мог преодолеть это ограничение, поэтому следующие примеры менее выразительны, чем могли бы быть.
# In an encoding where each character in the input string is three bytes wide,
# Selecting bytes 1-6 yields the first two characters (correct)
$ LC_ALL=ja_JP.UTF-8 cut -b1-6 kanji.utf-8.txt
...first two characters of each line...
# Selecting all three characters with the -c switch doesn’t work.
# It behaves like -b, contrary to documentation.
$ LC_ALL=ja_JP.UTF-8 cut -c1-3 kanji.utf-8.txt
...first character of each line...
# In this case, an illegal UTF-8 string is produced.
# The -n switch would prevent this, if implemented.
$ LC_ALL=ja_JP.UTF-8 cut -n -c2 kanji.utf-8.txt
...second byte, which is an illegal UTF-8 sequence...
Если ваши символы находятся за пределами диапазона ASCII, и вы хотите использовать cut
, вы всегда должны знать ширину символов в кодировке и использовать -b
соответственно. Если и когда -c
начинает работать как задокументированный, вам не придется менять свои скрипты.
4. Сравнение скорости
cut
ограничения «s есть люди , сомневающихся свою полезность. Фактически, та же функциональность может быть достигнута благодаря более мощным, более популярным утилитам. Однако преимуществом cut
является его производительность . Ниже приведены некоторые сравнения скорости. test.txt
имеет три миллиона строк с пятью полями, разделенными пробелами. Для awk
теста использовался mawk
, потому что он быстрее, чем GNU awk
. Сама оболочка (последняя строка) является наихудшим исполнителем. Временные значения (в секундах) - это то, что команда time
дает как реальное время .
(Чтобы избежать недоразумений: все тестируемые команды дали одинаковый результат с данным вводом, но они, конечно, не эквивалентны и будут давать разные результаты в разных ситуациях, в частности, если поля были разделены переменным числом пробелов)
команда | Время |
---|---|
cut -d ' ' -f1,2 test.txt | 1.138s |
awk '{print $1 $2}' test.txt | 1.688s |
join -a1 -o1.1,1.2 test.txt /dev/null | 1.767s |
perl -lane 'print "@F[1,2]"' test.txt | 11.390s |
grep -o '^\([^ ]*\) \([^ ]*\)' test.txt | 22.925s |
sed -e 's/^\([^ ]*\) \([^ ]*\).*$/\1 \2/' test.txt | 52.122s |
while read ab _; do echo $a $b; done <test.txt | 55.582s |
5. Справочные справочные страницы
Основное использование
Типичное использование файлов CSV-типа, где каждая строка состоит из полей, разделенных разделителем, указанным опцией -d
. Разделителем по умолчанию является символ TAB. Предположим, у вас есть файл данных data.txt
с такими строками, как
0 0 755 1482941948.8024
102 33 4755 1240562224.3205
1003 1 644 1219943831.2367
затем
# extract the third space-delimited field
$ cut -d ' ' -f3 data.txt
755
4755
644
# extract the second dot-delimited field
$ cut -d. -f2 data.txt
8024
3205
2367
# extract the character range from the 20th through the 25th character
$ cut -c20-25 data.txt
948.80
056222
943831
Как обычно, между переключателем и его параметром могут быть дополнительные пробелы: -d,
совпадает с -d ,
GNU cut
позволяет указать параметр --output-delimiter
: (независимая функция этого примера заключается в том, что точку с запятой в качестве входного разделителя необходимо экранировать, чтобы избежать его специальной обработки оболочкой)
$ cut --output-delimiter=, -d\; -f1,2 <<<"a;b;c;d"
a,b
Только один разделитель
У вас не может быть более одного разделителя: если вы укажете что-то вроде -d ",;:"
, некоторые реализации будут использовать только первый символ в качестве разделителя (в данном случае - запятую). Другие реализации (например, GNU cut
) будут давать вы получите сообщение об ошибке.
$ cut -d ",;:" -f2 <<<"J.Smith,1 Main Road,cell:1234567890;land:4081234567"
cut: the delimiter must be a single character
Try `cut --help' for more information.
Повторные разделители интерпретируются как пустые поля
$ cut -d, -f1,3 <<<"a,,b,c,d,e"
a,b
довольно очевидна, но с помощью строк с разделителями по пространству это может быть менее очевидным для некоторых
$ cut -d ' ' -f1,3 <<<"a b c d e"
a b
cut
не может использоваться для анализа аргументов, как это делают оболочки и другие программы.
Нет цитирования
Невозможно защитить разделитель. Таблицы и аналогичное программное обеспечение для обработки CSV обычно могут распознавать символ цитирования текста, который позволяет определять строки, содержащие разделитель. С cut
вы не можете.
$ cut -d, -f3 <<<'John,Smith,"1, Main Street"'
"1
Извлечение, а не манипулирование
Вы можете извлекать только части строк, а не изменять порядок или повторять поля.
$ cut -d, -f2,1 <<<'John,Smith,USA' ## Just like -f1,2
John,Smith
$ cut -d, -f2,2 <<<'John,Smith,USA' ## Just like -f2
Smith