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

10

мой текстовый файл выглядит следующим образом:

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

    
задан O.E 23.10.2017 в 10:02
источник

8 ответов

22

Если есть только один знак = , вы можете удалить все до и включая = следующим образом:

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

Если вы хотите изменить исходный файл, используйте параметр -i после тестирования:

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

Примечания

  • -r используют ERE, поэтому нам не нужно бежать ( и )
  • s/old/new заменить old с new
  • .* любое количество символов
  • (things) save things в backreference позже с , и т. д.
ответ дан Zanna 23.10.2017 в 10:06
источник
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
    
ответ дан heemayl 23.10.2017 в 12:03
13

Я решил сравнить различные решения, перечисленные здесь. Для этого я создал большой файл на основе содержимого, предоставленного 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
    
    real    0m58.539s
    user    0m58.416s
    sys     0m0.108s
    
  • sed -ri 's/.* = (.*)//'

    $ time sed -ri 's/.* = (.*)//' input.file
    
    real    0m26.936s
    user    0m22.836s
    sys     0m4.092s
    

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

    $ time sed -r 's/.* = (.*)//' input.file > output.file
    
    real    0m19.734s
    user    0m19.672s
    sys     0m0.056s
    
  • gawk '{gsub(".*= ", "");print}'

    $ time gawk '{gsub(".*= ", "");print}' input.file > output.file
    
    real    0m5.644s
    user    0m5.568s
    sys     0m0.072s
    
  • rev | cut -d' ' -f1 | rev

    $ time rev input.file | cut -d' ' -f1 | rev  > output.file
    
    real    0m3.703s
    user    0m2.108s
    sys     0m4.916s
    
  • grep -oP '.*= \K.*'

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

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

    $ time perl -i.bak -pe 's/.*= //' input.file
    
    real    0m3.187s
    user    0m3.128s
    sys     0m0.056s
    
    $ time perl -pe 's/.*= //' input.file > output.file
    
    real    0m3.138s
    user    0m3.036s
    sys     0m0.100s
    
  • awk '{print $NF}'

    $ time awk '{print $NF}' input.file  > output.file
    
    real    0m1.251s
    user    0m1.164s
    sys     0m0.084s
    
  • cut -c 35-

    $ time cut -c 35- input.file  > output.file
    
    real    0m0.352s
    user    0m0.284s
    sys     0m0.064s
    
  • cut -d= -f2

    $ time cut -d= -f2 input.file  > output.file
    
    real    0m0.328s
    user    0m0.260s
    sys     0m0.064s
    

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

    
ответ дан pa4080 24.10.2017 в 16:56
12

С grep и -P для PCRE (интерпретируйте шаблон как P erl- < strong> C ompatible R egular E ) и -o для печати только сопоставленного шаблона. Уведомление \K будет игнорировать согласованную часть, пришедшую перед собой.

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

Или вы могли бы вместо этого использовать cut .

cut -d= -f2 infile
    
ответ дан sddgob 23.10.2017 в 12:21
11

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

cut -c 35- input.txt > output.txt
    
ответ дан David Foerster 23.10.2017 в 14:56
6

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

$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
    
ответ дан f1nan 23.10.2017 в 16:15
5

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

grep -oE '\S+$' file

grep в Ubuntu , при вызове -E или -P принимает значение < a href="https://www.regular-expressions.info/shorthand.html"> сокращенное \s означает пробельный символ (на практике обычно пробел или табуляция) и \S означают все, что не одно. Используя квантификатор + и end-of-line anchor $ , шаблон \S+$ соответствует одному или нескольким незанятым в конце строки . Вы можете использовать -P вместо -E ; значение в этом случае совпадает с другим механизмом регулярных выражений , поэтому они могут иметь разные характеристики производительности .

Это эквивалентно Avinash Радж прокомментировал решение (просто с более легким, более компактным синтаксисом):

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
  • WOW !! Метод cut в ответ αғsнιη , cut -d= -f2 file , на порядок быстрее, чем даже более быстрая версия моего пути! Это был победитель в эталон теста pa4080 , который охватывал больше методов, чем этот, но с меньшим объемом ввода - и вот почему Я выбрал его, из всех других методов, для включения в мой тест. Если производительность важна или файлы огромны, я думаю, что метод cut αғsnιη должен использоваться.

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

ответ дан Eliah Kagan 24.10.2017 в 21:15
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
  • Я упоминаю этот подход, потому что он в несколько раз быстрее, чем в ответах Zanna в Zanna
  • .

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...
    
ответ дан pa4080 24.10.2017 в 08:02