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

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

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

10
задан 23 October 2017 в 13:10

24 ответа

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

$ 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 на [ f11] .* любое число любых символов (things) сохранить things в обратную ссылку позже с помощью \1, \2 и т. д.
22
ответ дан 22 May 2018 в 17:14
  • 1
    Спасибо, что сработало. Я использовал эту команду для перезаписывания существующего файла: sed -i -r 's /.*= (. *) / \ 1 /' time.txt Можете ли вы объяснить, как это работает? – O.E 23 October 2017 в 13:09
  • 2
    Почему бы не избежать обратной ссылки? s/^.*= // будет работать одинаково хорошо, поскольку правильное значение находится в конце строки. – jpaugh 24 October 2017 в 20:58
  • 3
    @jpaugh Отчасти потому, что слишком поздно менять свой ответ, который был первым опубликован - другие уже дали решение, которое вы упомянули, и другие более эффективные способы для этого случая :) Но, возможно, показ того, как использовать \1 и т. д., имеет некоторую ценность для людей, которые приходят на этот вопрос при поиске, у кого нет такой простой проблемы – Zanna 24 October 2017 в 21:05
  • 4
    @ Занна Это более общее, по крайней мере. – jpaugh 24 October 2017 в 21:07

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

$ 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 и т. д.
22
ответ дан 18 July 2018 в 04:46

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

$ 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 и т. д.
22
ответ дан 24 July 2018 в 18:09

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

awk '{print $NF}' file.txt
NF является переменной awk, расширяется до количества полей в записи (строке), следовательно [ f6] (обратите внимание на $ спереди) содержит значение последнего поля.

Пример:

% 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
20
ответ дан 22 May 2018 в 17:14

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

Я создал простой файл с именем 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
Затем я выполнил этот цикл:
for i in {1..100}; do cat input.file | tee -a input.file; done
Окно терминала заблокировано. Я выполнил killall tee с другого терминала. Затем я просмотрел содержимое файла с помощью команд: less input.file и cat input.file. Это выглядело хорошо, кроме последней строки. Поэтому я удалил последнюю строку и создал резервную копию: cp input.file{,.copy} (из-за команд, которые используют опцию inplace). Окончательный счетчик строк в файле 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/.* = (.*)/\1/' $ time sed -ri 's/.* = (.*)/\1/' input.file real 0m26.936s user 0m22.836s sys 0m4.092s Альтернативно, если мы перенаправляем вывод в новый файл, команда выполняется быстрее: $ time sed -r 's/.* = (.*)/\1/' 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 не дает большой разницы в производительности здесь) [ f11] $ 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

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

13
ответ дан 22 May 2018 в 17:14
  • 1
  • 2
    Можете ли вы дать больше информации о том, как вы создали этот файл? Кроме того, как wc -l выводит три цифры? Когда другие параметры не передаются, параметр -l должен подавлять все, кроме строки. – Eliah Kagan 24 October 2017 в 19:14
  • 3
    @ EliahKagan, сделано. Я обновил ответ. – pa4080 24 October 2017 в 19:40
  • 4
    Ах, я вижу - пробелы были разделителями групп цифр. (Had wc действительно отображал эти пробелы? Существуют ли языковые настройки, для которых он будет это делать?) Спасибо за обновление! – Eliah Kagan 24 October 2017 в 19:43
  • 5
    @EliahKagan: Наконец, я еще раз прочитал ваши вопросы о wc. Я не знаю, где мой ум сегодня был рано, но я действительно не мог понять их. Так что действительно пробелы были разделителями групп цифр , а wc не добавляли их :) – pa4080 24 October 2017 в 23:06

С grep и -P для PCRE (интерпретируйте шаблон как регулярное выражение, совместимое с Perl) и -o для печати только одного шаблона. Уведомление \K будет игнорировать согласованную часть, пришедшую перед собой.

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

Или вы могли бы использовать команду grep .

cut -d= -f2 infile
12
ответ дан 22 May 2018 в 17:14
  • 1
    В дополнение к запуску самых быстрых из всех методов, проверенных в контрольном пункте pa4080 , , метод cut в этом ответе также был явным победителем в , который был меньшим эталоном, который я провел , который тестировал меньшее количество методов, но использовал больший входной файл. Это было более чем в десять раз быстрее, чем быстрый вариант метода, который мне лично нравится (и что мой ответ в основном о). – Eliah Kagan 25 October 2017 в 00:20

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

cut -c 35- input.txt > output.txt
11
ответ дан 22 May 2018 в 17:14

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

$ rev your_file | cut -d' ' -f1 | rev
0.000205348
0.000265725
0.000322823
0.000376445
0.000425341
6
ответ дан 22 May 2018 в 17:14

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

grep -oE '\S+$' file

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

Это эквивалентно grep в Ubuntu (просто с более легким, более компактным синтаксисом):

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

Я запускал его дважды в том случае, когда имел значение порядок (как это иногда бывает для I / O-тяжелого задачи), и потому, что у меня не было машины, которая не делала другие вещи в фоновом режиме, которые могли бы исказить результаты. Из этих результатов я заключаю следующее, по крайней мере временно, и для входных файлов размера, который я использовал:

Ничего себе! Передача -P (для использования PCRE), а не -G (по умолчанию, когда диалект не указан) или -E сделал grep быстрее на порядок. Поэтому для больших файлов лучше использовать эту команду, чем приведенная выше:
grep -oP '\S+$' file
WOW !! Метод cut в ответе αғsнι, cut -d= -f2 file, на порядок быстрее, чем даже более быстрая версия моего пути! Это был победитель в тестах pa4080, который охватывал больше методов, чем этот, но с меньшим объемом ввода - и именно поэтому я выбрал его, из всех других методов, для включения в мой тест. Если производительность важна или файлы огромны, я думаю, что метод αғsnιη cut следует использовать. Это также служит напоминанием о том, что простые утилиты cut и paste не должны быть забыты и, возможно, предпочтительнее, когда это применимо, хотя есть более сложные инструменты, такие как grep, которые часто предлагаются в качестве первой линии решений (и что я лично больше привык к использованию).
5
ответ дан 22 May 2018 в 17:14

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)

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

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

или (но медленнее, чем указано выше):

sed -i.bak '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)

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

gawk '{gsub(".*= ", "");print}' input.file > output.file

Из perl --help:

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...
4
ответ дан 22 May 2018 в 17:14

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

Я создал простой файл с именем 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 Затем я выполнил этот цикл: for i in {1..100}; do cat input.file | tee -a input.file; done Окно терминала заблокировано. Я выполнил killall tee с другого терминала. Затем я просмотрел содержимое файла с помощью команд: less input.file и cat input.file. Это выглядело хорошо, кроме последней строки. Поэтому я удалил последнюю строку и создал резервную копию: cp input.file{,.copy} (из-за команд, которые используют опцию inplace). Окончательный счетчик строк в файле 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/.* = (.*)/\1/' $ time sed -ri 's/.* = (.*)/\1/' input.file real 0m26.936s user 0m22.836s sys 0m4.092s Альтернативно, если мы перенаправляем вывод в новый файл, команда выполняется быстрее: $ time sed -r 's/.* = (.*)/\1/' 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

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

13
ответ дан 18 July 2018 в 04:46

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

cut -c 35- input.txt > output.txt
11
ответ дан 18 July 2018 в 04:46

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

grep -oE '\S+$' file

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

Это эквивалентно grep в Ubuntu (просто с более легким, более компактным синтаксисом):

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

Я запускал его дважды в том случае, когда имел значение порядок (как это иногда бывает для I / O-тяжелого задачи), и потому, что у меня не было машины, которая не делала другие вещи в фоновом режиме, которые могли бы исказить результаты. Из этих результатов я заключаю следующее, по крайней мере временно, и для входных файлов размера, который я использовал:

Ничего себе! Передача -P (для использования PCRE), а не -G (по умолчанию, когда диалект не указан) или -E сделал grep быстрее на порядок. Поэтому для больших файлов лучше использовать эту команду, чем приведенная выше: grep -oP '\S+$' file WOW !! Метод cut в ответе αғsнι, cut -d= -f2 file, на порядок быстрее, чем даже более быстрая версия моего пути! Это был победитель в тестах pa4080, который охватывал больше методов, чем этот, но с меньшим объемом ввода - и именно поэтому я выбрал его, из всех других методов, для включения в мой тест. Если производительность важна или файлы огромны, я думаю, что метод αғsnιη cut следует использовать. Это также служит напоминанием о том, что простые утилиты cut и paste не должны быть забыты и, возможно, предпочтительнее, когда это применимо, хотя есть более сложные инструменты, такие как grep, которые часто предлагаются в качестве первой линии решений (и что я лично больше привык к использованию).
5
ответ дан 18 July 2018 в 04:46

Это задание для 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
21
ответ дан 18 July 2018 в 04:46

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)

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

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

или (но медленнее, чем указано выше):

sed -i.bak '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)

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

gawk '{gsub(".*= ", "");print}' input.file > output.file

Из perl --help:

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...
4
ответ дан 18 July 2018 в 04:46

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

$ rev your_file | cut -d' ' -f1 | rev 0.000205348 0.000265725 0.000322823 0.000376445 0.000425341
6
ответ дан 18 July 2018 в 04:46

С grep и -P для PCRE (интерпретируйте шаблон как регулярное выражение, совместимое с Perl) и -o для печати только одного шаблона. Уведомление \K будет игнорировать согласованную часть, пришедшую перед собой.

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

Или вы могли бы использовать команду grep .

cut -d= -f2 infile
12
ответ дан 18 July 2018 в 04:46

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

Я создал простой файл с именем 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 Затем я выполнил этот цикл: for i in {1..100}; do cat input.file | tee -a input.file; done Окно терминала заблокировано. Я выполнил killall tee с другого терминала. Затем я просмотрел содержимое файла с помощью команд: less input.file и cat input.file. Это выглядело хорошо, кроме последней строки. Поэтому я удалил последнюю строку и создал резервную копию: cp input.file{,.copy} (из-за команд, которые используют опцию inplace). Окончательный счетчик строк в файле 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/.* = (.*)/\1/' $ time sed -ri 's/.* = (.*)/\1/' input.file real 0m26.936s user 0m22.836s sys 0m4.092s Альтернативно, если мы перенаправляем вывод в новый файл, команда выполняется быстрее: $ time sed -r 's/.* = (.*)/\1/' 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

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

13
ответ дан 24 July 2018 в 18:09
  • 1
  • 2
    Можете ли вы дать больше информации о том, как вы создали этот файл? Кроме того, как wc -l выводит три цифры? Когда другие параметры не передаются, параметр -l должен подавлять все, кроме строки. – Eliah Kagan 24 October 2017 в 19:14
  • 3
    @ EliahKagan, сделано. Я обновил ответ. – pa4080 24 October 2017 в 19:40
  • 4
    Ах, я вижу - пробелы были разделителями групп цифр. (Had wc действительно отображал эти пробелы? Существуют ли языковые настройки, для которых он будет это делать?) Спасибо за обновление! – Eliah Kagan 24 October 2017 в 19:43
  • 5
    @EliahKagan: Наконец, я еще раз прочитал ваши вопросы о wc. Я не знаю, где мой ум сегодня был рано, но я действительно не мог понять их. Так что действительно пробелы были разделителями групп цифр , а wc не добавляли их :) – pa4080 24 October 2017 в 23:06

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

cut -c 35- input.txt > output.txt
11
ответ дан 24 July 2018 в 18:09

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

grep -oE '\S+$' file

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

Это эквивалентно grep в Ubuntu (просто с более легким, более компактным синтаксисом):

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

Я запускал его дважды в том случае, когда имел значение порядок (как это иногда бывает для I / O-тяжелого задачи), и потому, что у меня не было машины, которая не делала другие вещи в фоновом режиме, которые могли бы исказить результаты. Из этих результатов я заключаю следующее, по крайней мере временно, и для входных файлов размера, который я использовал:

Ничего себе! Передача -P (для использования PCRE), а не -G (по умолчанию, когда диалект не указан) или -E сделал grep быстрее на порядок. Поэтому для больших файлов лучше использовать эту команду, чем приведенная выше: grep -oP '\S+$' file WOW !! Метод cut в ответе αғsнι, cut -d= -f2 file, на порядок быстрее, чем даже более быстрая версия моего пути! Это был победитель в тестах pa4080, который охватывал больше методов, чем этот, но с меньшим объемом ввода - и именно поэтому я выбрал его, из всех других методов, для включения в мой тест. Если производительность важна или файлы огромны, я думаю, что метод αғsnιη cut следует использовать. Это также служит напоминанием о том, что простые утилиты cut и paste не должны быть забыты и, возможно, предпочтительнее, когда это применимо, хотя есть более сложные инструменты, такие как grep, которые часто предлагаются в качестве первой линии решений (и что я лично больше привык к использованию).
5
ответ дан 24 July 2018 в 18:09

Это задание для 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
21
ответ дан 24 July 2018 в 18:09

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)

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

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

или (но медленнее, чем указано выше):

sed -i.bak '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)

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

gawk '{gsub(".*= ", "");print}' input.file > output.file

Из perl --help:

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...
4
ответ дан 24 July 2018 в 18:09

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

$ rev your_file | cut -d' ' -f1 | rev 0.000205348 0.000265725 0.000322823 0.000376445 0.000425341
6
ответ дан 24 July 2018 в 18:09

С grep и -P для PCRE (интерпретируйте шаблон как регулярное выражение, совместимое с Perl) и -o для печати только одного шаблона. Уведомление \K будет игнорировать согласованную часть, пришедшую перед собой.

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

Или вы могли бы использовать команду grep .

cut -d= -f2 infile
12
ответ дан 24 July 2018 в 18:09
  • 1
    В дополнение к запуску самых быстрых из всех методов, проверенных в контрольном пункте pa4080 , , метод cut в этом ответе также был явным победителем в , который был меньшим эталоном, который я провел , который тестировал меньшее количество методов, но использовал больший входной файл. Это было более чем в десять раз быстрее, чем быстрый вариант метода, который мне лично нравится (и что мой ответ в основном о). – Eliah Kagan 25 October 2017 в 00:20

Другие вопросы по тегам:

Похожие вопросы: