Как удалить отдельные слова из строк текстового файла?

Мой текстовый файл выглядит так:

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) из моих строк, чтобы получить только значения. Как я должен это делать?

8 ответов

Решение

Если есть только один = подписать, вы можете удалить все до и в том числе = как это:

$ 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, так далее.

Это работа для 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

Я решил сравнить разные решения, перечисленные здесь. Для этой цели я создал большой файл на основе содержимого, предоставленного OP:

  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 '[^ [: space:]] \ + $' input.file> output.file
    
    реальный 0m58.539s
    пользователь 0m58.416s
    sys 0m0.108s
    
  • sed -ri 's/.* = (.*)/\1/'

    $ time sed -ri 's /.* = (. *) / \ 1 /' input.file
    
    реальный 0m26.936s
    пользователь 0m22.836s
    sys     0m4.092s
    

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

    $ time sed -r 's /.* = (. *) / \ 1 /' input.file> output.file
    
    реальный 0m19.734s
    пользователь 0m19.672s
    sys 0m0.056s
    
  • gawk '{gsub(".*= ", "");print}'

    $ time gawk '{gsub (". * =", ""); print}' input.file> output.file
    
    реальный 0m5.644s
    пользователь 0m5.568s
    sys 0m0.072s
    
  • rev | cut -d' ' -f1 | rev

    $ time rev input.file | cut -d '' -f1 | rev> output.file
    
    реальный 0m3.703s
    пользователь 0m2.108s
    sys 0m4.916s
    
  • grep -oP '.*= \K.*'

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

    $ time sed 's /.*= //' input.file> output.file
    
    реальный 0m3.310s
    пользователь 0m3.212s
    sys 0m0.092s
    
  • perl -pe 's/.*= //' ( -i опция не дает большой разницы в производительности)

    $ time perl -i.bak -pe 's /.*= //' input.file
    
    реальный 0m3.187s
    пользователь 0m3.128s
    sys 0m0.056s
    
    $ time perl -pe 's /.*= //' input.file> output.file
    
    реальный 0m3.138s
    пользователь 0m3.036s
    sys 0m0.100s
    
  • awk '{print $NF}'

    $ time awk '{print $ NF}' input.file> output.file
    
    реальный 0m1.251s
    пользователь 0m1.164s
    sys 0m0.084s
    
  • cut -c 35-

    $ time cut -c 35- input.file> output.file
    
    реальный 0m0.352s
    пользователь 0m0.284s
    sys 0m0.064s
    
  • cut -d= -f2

    $ time cut -d = -f2 input.file> output.file real 0m0.328s пользователь 0m0.260s
    sys     0m0.064s 

Источник идеи.

С grep и -P за то PCRE (Интерпретировать паттерн как совместимую регулярную экспрессию) и -o печатать сопоставленный образец в одиночку. \K notify будет игнорировать подходящую часть перед собой.

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

Или вы могли бы использовать cut команда вместо

cut -d= -f2 infile

Поскольку префикс строки всегда имеет одинаковую длину (34 символа), вы можете использовать cut:

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

Обратное содержимое файла с revнаправить вывод в cut с пробелом в качестве разделителя и 1 в качестве целевого поля, затем снова измените его, чтобы получить исходное число:

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

Это просто, кратко и легко написать, понять и проверить, и мне лично это нравится:

grep -oE '\S+$' file

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

Это эквивалентно прокомментированному решению Avinash Raj (только с более простым и компактным синтаксисом):

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 нιη, cut -d= -f2 file, на порядок быстрее, чем даже более быстрая версия моего пути! Он также стал победителем в тесте PA4080, который охватывал больше методов, чем этот, но с меньшим вводом - и именно поэтому я выбрал его, из всех других методов, для включения в мой тест. Если производительность важна или файлы огромны, я думаю, что cut метод должен быть использован.

    Это также служит напоминанием о том, что простой cut а также paste Утилиты не должны быть забыты, и, возможно, их следует отдавать предпочтение, когда это применимо, хотя существуют более сложные инструменты, такие как grep которые часто предлагаются в качестве решений первой линии (и которые я лично больше использую).

perl - замени шаблон /.*= / с пустой строкой //:

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...
    
Другие вопросы по тегам