Як видалити окремі слова з рядків текстового файлу?


13

мій текстовий файл виглядає так:

Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341

тепер я хочу видалити Liquid penetration 95% mass (m)зі своїх рядків, щоб отримати лише значення. Як мені це зробити?


3
простоgrep -o '[^[:space:]]\+$' file
Avinash Raj

@AvinashRaj: На даний момент це рішення отримує "медаль шпаклівки" :)
pa4080

2
@ pa4080 Принаймні для тестуваного нами входу (10М рядків) загальний підхід Avinash Raj можна зробити на порядок швидшим за допомогою PCRE. (Я міг би підтвердити, що двигун, а не зразок, відповідає, оскільки GNU grep приймає \S+$або один, -Eабо інший -P.) Тож подібне рішення не є за своєю суттю повільним. Але я до сих пір не можу домогтися цього cutспособу , близького до методу αғsnιη , який також переміг у вашому орієнтирі .
Елія Каган

Відповіді:


22

Якщо є лише одна =ознака, ви можете видалити все до цього і включити =так:

$ sed -r 's/.* = (.*)/\1/' file
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

Якщо ви хочете змінити вихідний файл, скористайтеся -iопцією після тестування:

sed -ri 's/.* = (.*)/\1/' file

Примітки

  • -rвикористовувати ERE, щоб нам не довелося бігти (і)
  • s/old/newзамінити oldнаnew
  • .* будь-яка кількість будь-яких символів
  • (things)зберегти thingsна зворотне посилання пізніше \1, \2і т.д.

Спасибі це спрацювало. Я використовував цю команду для заміни наявного файлу: sed -i -r 's /.*= (. *) / \ 1 /' time.txt Чи можете ви пояснити, як це працює?
ОЕ

Чому б не уникнути зворотної референції? s/^.*= //буде працювати однаково добре, оскільки правильне значення знаходиться в кінці рядка.
jpaugh

@jpaugh Ну частково тому, що вже пізно міняти мою відповідь, яка була першою, яку опублікували - інші вже дали рішення, яке ви згадали, та інші більш ефективні способи для цього випадку :) Але, можливо, показ того, як використовувати \1тощо, має певне значення для людей, які зверніться до цього питання під час пошуку, у кого немає такої простої проблеми
Zanna

@Zanna Це, принаймні, більш загальне.
jpaugh

21

Це робота для awk; припускаючи, що значення трапляються лише в останньому полі (відповідно до вашого прикладу):

awk '{print $NF}' file.txt
  • NFє awkзмінною, розширюється на кількість полів у записі (рядку), отже $NF(зверніть увагу на $фронт) містить значення останнього поля.

Приклад:

% cat temp.txt 
Liquid penetration 95% mass (m) = 0.000205348
Liquid penetration 95% mass (m) = 0.000265725
Liquid penetration 95% mass (m) = 0.000322823
Liquid penetration 95% mass (m) = 0.000376445
Liquid penetration 95% mass (m) = 0.000425341

% awk '{print $NF}' temp.txt
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

13

Я вирішив порівняти різні рішення, перелічені тут. Для цього я створив великий файл на основі вмісту, наданого ОП:

  1. Я створив простий файл під назвою input.file:

    $ cat input.file
    Liquid penetration 95% mass (m) = 0.000205348
    Liquid penetration 95% mass (m) = 0.000265725
    Liquid penetration 95% mass (m) = 0.000322823
    Liquid penetration 95% mass (m) = 0.000376445
    Liquid penetration 95% mass (m) = 0.000425341
    
  2. Потім я виконав цю петлю:

    for i in {1..100}; do cat input.file | tee -a input.file; done
    
  3. Вікно терміналу було заблоковано. Я виконаний killall teeз іншого терміналу. Потім я вивчив вміст файлу командами: less input.fileі cat input.file. Це добре виглядало, крім останнього рядка. Тому я видалив останній рядок і створив резервну копію: cp input.file{,.copy}(через команди, які використовують параметр inplace ).

  4. Кінцевий підрахунок рядків у файлі input.file- 2 192 473 . Я отримав це число за командою wc:

    $ cat input.file | wc -l
    2192473
    

Ось результат порівняння:

  • grep -o '[^[:space:]]\+$'

    $ time grep -o '[^ [: простір:]] \ + $' input.file> output.file
    
    реальні 0м58.539с
    користувач 0m58.416s
    sys 0m0.108s
    
  • sed -ri 's/.* = (.*)/\1/'

    $ time sed -ri 's /.* = (. *) / \ 1 /' input.file
    
    реальні 0м26.936с
    користувач 0m22.836s
    sys 0m4.092s
    

    Крім того, якщо ми переспрямовуємо вихід на новий файл, команда швидше:

    $ time sed -r 's /.* = (. *) / \ 1 /' input.file> output.file
    
    реальні 0м19.734с
    користувач 0m19.672s
    sys 0m0.056s
    
  • gawk '{gsub(".*= ", "");print}'

    $ time gawk '{gsub (". * =", ""); print}' input.file> output.file
    
    реальні 0м5.644с
    користувач 0m5.568s
    sys 0m0.072s
    
  • rev | cut -d' ' -f1 | rev

    $ time rev input.file | вирізати -d '' -f1 | rev> output.file
    
    реальні 0м3.703с
    користувач 0м2.108с
    sys 0m4.916s
    
  • grep -oP '.*= \K.*'

    $ time grep -oP '. * = \ K. *' input.file> output.file
    
    реальні 0м3.328с
    користувач 0m3.252s
    sys 0m0.072s
    
  • sed 's/.*= //' (відповідно -iопція робить команду в кілька разів повільнішою)

    $ time sed 's /.*= //' input.file> output.file
    
    реальні 0м3.310с
    користувач 0m3.212s
    sys 0m0.092s
    
  • perl -pe 's/.*= //' ( -iопція не дає великої різниці в продуктивності тут)

    $ time perl -i.bak -pe 's /.*= //' input.file
    
    реальні 0м3.187с
    користувач 0m3.128s
    sys 0m0.056s
    
    $ time perl -pe 's /.*= //' input.file> output.file
    
    реальні 0м3.138с
    користувач 0m3.036s
    sys 0m0.100s
    
  • awk '{print $NF}'

    $ time awk '{print $ NF}' input.file> output.file
    
    реальні 0м1.251с
    користувач 0m1.164s
    sys 0m0.084s
    
  • cut -c 35-

    $ cut cut -c 35- input.file> output.file
    
    реальні 0м0.352с
    користувач 0m0.284s
    sys 0m0.064s
    
  • cut -d= -f2

    $ cut cut -d = -f2 input.file> output.file
    
    реальні 0м0.328с
    користувач 0m0.260s
    sys 0m0.064s
    

Джерело ідеї.


2
тому моє cut -d= -f2рішення перемагає. ха-ха
αғsnιη

Чи можете ви надати більше інформації про те, як ви створили цей файл? Крім того, як wc -lвиводиться три числа? Якщо інші параметри не передані, -lопція повинна придушувати все, крім підрахунку рядків.
Елія Каган

@EliahKagan, готово. Я оновив відповідь.
pa4080

Ах, я бачу - пробіли були розділовими групами. (Чи wcсправді відображалися ці пробіли? Чи є параметри локалі, для яких це буде робити?) Дякую за оновлення!
Елія Каган

@EliahKagan: Нарешті я ще раз прочитав ваші запитання wc. Я не знаю, де сьогодні була моя дотепність, але я насправді не міг їх зрозуміти. Тож пробіли були розрядними розділовими групами , і wcне додавали їх :)
pa4080

12

З grepі -Pдля, що мають PCRE(Інтерпретувати візерунок як P erl- C сумісний R- кутовий Е- вираз) та тільки -oдля друку відповідного шаблону. Повідомлення \Kбуде ігнорувати відповідну частину, що передує собі.

$ grep -oP '.*= \K.*' infile
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

Або ви можете використовувати cutкоманду замість цього.

cut -d= -f2 infile

2
На додаток до запуску найшвидший з усіх методів , випробуваних в тесті pa4080 в , метод в цій відповіді також був явним переможцем у меншому тесті я побіг , що випробувані методи , але менше використовується більший вхідний файл. Це було набагато в десять разів швидше, ніж швидкий варіант методу, який мені особисто подобається (і в основному моя відповідь стосується). cut
Елія Каган

11

Оскільки префікс рядка завжди має однакову довжину (34 символи), ви можете використовувати cut:

cut -c 35- < input.txt > output.txt

6

Зворотний вміст файлу за допомогою rev, передайте висновок у cutпробіл як роздільник та 1 як цільове поле, а потім поверніть його знову, щоб отримати початкове число:

$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341

5

Це просто, коротко і легко писати, розуміти та перевіряти, і мені особисто це подобається:

grep -oE '\S+$' file

grepв Ubuntu , коли викликається -Eабо -P, використовується скорочення \s для позначення символу пробілу (на практиці зазвичай це пробіл або вкладка) і \Sозначає все, що не є одним. Використовуючи квантор+ і якір кінця рядка$ , шаблон \S+$узгоджується з одним або декількома непустими в кінці рядка . Ви можете використовувати -Pзамість -E; значення в цьому випадку однакове, але використовується інший двигун регулярних виразів , тому вони можуть мати різні експлуатаційні характеристики .

Це еквівалентно коментованому рішенням Авінаша Раджа (лише з легшим, компактнішим синтаксисом):

grep -o '[^[:space:]]\+$' file

Ці підходи не працюватимуть, якщо після числа може бути пробіл пробілу . Вони можуть бути модифіковані так, але вони не бачать сенсу займатися цим. Хоча іноді доцільно узагальнювати рішення для роботи в більшій кількості випадків, це не практично так часто, як люди схильні вважати, тому що зазвичай неможливо дізнатися, яким із багатьох різних несумісних способів проблема в кінцевому підсумку може знадобитися бути узагальненими.


Продуктивність іноді є важливою увагою. Це питання не передбачає, що введення дуже велике, і, ймовірно, кожен метод, розміщений тут, є досить швидким. Однак, якщо потрібна швидкість, ось невеликий орієнтир у вхідному файлі на десять мільйонів рядків:

$ perl -e 'print((<>) x 2000000)' file > bigfile
$ du -sh bigfile
439M    bigfile
$ wc -l bigfile
10000000 bigfile
$ TIMEFORMAT=%R
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
819.565
$ time grep -oE '\S+$' bigfile > bigfile.out
816.910
$ time grep -oP '\S+$' bigfile > bigfile.out
67.465
$ time cut -d= -f2 bigfile > bigfile.out
3.902
$ time grep -o '[^[:space:]]\+$' bigfile > bigfile.out
815.183
$ time grep -oE '\S+$' bigfile > bigfile.out
824.546
$ time grep -oP '\S+$' bigfile > bigfile.out
68.692
$ time cut -d= -f2 bigfile > bigfile.out
4.135

Я запускав його двічі на випадок, коли замовлення було важливим (як це іноді робиться для важких завдань вводу / виводу) і тому, що у мене не було машини, яка б не робила інших матеріалів у фоновому режимі, які могли б перекривити результати. З цих результатів я, принаймні попередньо, і для вхідних файлів того розміру, який я використовував, роблю наступне:

  • Оце Так! Проходження -P(для використання PCRE ), а не -G(за замовчуванням, коли не вказано діалект) або -Eзроблено grepшвидше на порядок. Тому для великих файлів може бути краще використовувати цю команду, ніж показана вище:

    grep -oP '\S+$' file
  • ОГО!! cutМетод в відповіді αғsнιη в , є більш ніж на порядок величини швидше , ніж навіть більш швидка версія мого шляху! Він був переможцем і в еталоні pa4080 , який охоплював більше методів, ніж цей, але з меншим вкладом - і саме тому я вибрав його, з усіх інших методів, щоб включити до свого тесту. Якщо важлива продуктивність або файли величезні, я думаю , що слід використовувати метод αғsnιη .cut -d= -f2 filecut

    Це також служить нагадуванням про те, що про прості cutта pasteутиліти не слід забувати , і, можливо, їх слід віддавати перевагу, коли це можливо, навіть якщо є більш складні інструменти, такі grepяк часто пропонуються як рішення першого ряду (і що я особисто більше звик до використання).


4

perl- s вставте шаблон /.*= /порожнім рядком //:

perl -pe 's/.*= //' input.file > output.file
perl -i.bak -pe 's/.*= //' input.file
  • Від perl --help:

    -e program        one line of program (several -e's allowed, omit programfile)
    -p                assume loop like -n but print line also, like sed
    -i[extension]     edit <> files in place (makes backup if extension supplied)
    

sed - замініть візерунок порожнім рядком:

sed 's/.*= //' input.file > output.file

або (але повільніше, ніж вище) :

sed -i.bak 's/.*= //' input.file
  • Я згадую про такий підхід, тому що він у кілька разів швидший, ніж у відповіді Занні .

gawk- замініть візерунок ".*= "порожнім рядком "":

gawk '{gsub(".*= ", "");print}' input.file > output.file
  • Від man gawk:

    gsub(r, s [, t]) For each substring matching the regular expression r in the string t,
                     substitute the string s, and return the number of substitutions. 
                     If t is not supplied, use $0...
    
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.