Як зробити так, щоб команда 'cut' ставилася до таких же послідовних роздільників, як одна?


307

Я намагаюся витягнути певне (четверте) поле з текстового потоку, орієнтованого на стовпчик. Я намагаюся використовувати cutкоманду таким чином:

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

На жаль, cutне розглядається декілька пробілів як один роздільник. Я міг би пройти через awk

awk '{ printf $4; }'

або sed

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

щоб зруйнувати пробіли, але я хотів би знати, чи є спосіб вирішити cutі кілька роздільників?



Відповіді:


545

Спробуйте:

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

Із trчоловічої сторінки:

-s, --squeeze-повтори замінюють кожну послідовність введення повторюваного символу
                        що вказано в SET1 з одним явищем
                        цього характеру

24
Тут не потрібно cat. Ви можете перейти < text.txtбезпосередньо до tr. en.wikipedia.org/wiki/Cat_%28Unix%29#Useless_use_of_cat
arielf

1
Не впевнений, що це простіше, але ви збираєтесь об'єднатись, ви можете відмовитись від вирізання -dта перекласти прямо з декількох символів на вкладку. Наприклад: Я прийшов сюди, шукаючи спосіб автоматичного експорту мого дисплея:who am i | tr -s ' ()' '\t' | cut -f5
Лев,

Це не вилучає простір пробілів / пробілів (який може бути або не потрібен, але зазвичай не потрібен) на відміну від рішення awk. Рішення awk також набагато легше читати і менш дослівно.
n.caillou

-1 ПОПЕРЕДЖЕННЯ: ЦЕ НЕ ТОЖЕ, ЩО ЛІКУВАТИ СЕКВЕНТІАЛЬНІ ДЕЛІМЕТРИ, ЯК ОДНІ. Порівняйте echo "a b c" | cut -d " " -f2-,echo "a b c" | tr -s " " | cut -d " " -f2-
user541686

96

Як ви коментуєте своє запитання, awkце дійсно шлях. Використовувати cutможна разом із tr -sстисканням пробілів, як показує відповідь КЕВ .

Дозвольте, однак, проглянути всі можливі комбінації для майбутніх читачів. Пояснення є у розділі Тест.

тр | вирізати

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

awk

awk '{print $4}' file

баш

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

тр | вирізати

$ 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

баш

Це читає поля послідовно. Використовуючи, _ми вказуємо, що це викидна змінна як "незмінна змінна" для ігнорування цих полів. Таким чином, ми зберігаємо $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

2
awkце не тільки елегантно і просто, він також включений у VMware ESXi, де trйого немає.
користувач121391

2
@ user121391 ще одна причина використання awk!
fedorqui 'ТАК перестаньте шкодити'

@fedorqui Я ніколи не чув про підкреслення як про "мінливу змінну". Чи можете ви надати більше інформації про це?
BryKKan

1
@BryKKan Я дізнався про це в Greg's Як я можу прочитати файл (потік даних, змінний) рядок за рядком (та / або поле за полем)? : Деякі люди використовують змінну _, що викидається _, як "змінну небажаної", щоб ігнорувати поля. Він (або взагалі будь-яка змінна) також може використовуватися не один раз в одній readкоманді, якщо нам не байдуже, що в неї входить . Це може бути що завгодно, це просто те, що він якось став стандартним замість junk_varабо whatever:)
fedorqui 'ТАК перестаньте шкодити'

25

найкоротше / найдружніше рішення

Розчарувавшись у занадто великій кількості обмежень cut, я написав власну заміну, яку закликав 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/


4

Цей однолінійний Perl показує, наскільки тісно Perl пов'язаний з awk:

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

Однак @Fмасив autosplit починається з індексу, $F[0]а поля awk починаються з$1


3

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.