Какой у вас последний полезный однострочный Perl (или конвейер с Perl)?

Однострочник должен:

  • решить реальную проблему
  • не быть чрезмерно загадочным (должно быть легко понять и воспроизвести)
  • стоит потратить время на его написание (не должно быть слишком умным)

Ищу практические советы и рекомендации (дополнительные примеры для perldoc perlrun).

«последний» означает «окончательный», например, я никогда больше не напишу другого. Этого не случится. Я буду продолжать писать однострочники Perl, пока это будет приниматься подсказкой. Возможно, вы имели в виду «последний».

Randal Schwartz 03.10.2008 02:13

Спасибо. Я исправил заголовок. Время для моей последней трапезы еще не пришло :)

jfs 03.10.2008 05:11
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
15
2
12 885
24
Перейти к ответу Данный вопрос помечен как решенный

Ответы 24

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

Решение: переименовать все * .srt (файлы с субтитрами), чтобы они соответствовали * .avi (файлы с видео).

perl -e'while(<*.avi>) { s/avi$/srt/; rename <*.srt>, $_ }'

ПРЕДОСТЕРЕЖЕНИЕ: порядок сортировки исходных файлов видео и субтитров должен быть одинаковым.

Вот более подробная версия вышеупомянутого однострочника:

my @avi = glob('*.avi');
my @srt = glob('*.srt');

for my $i (0..$#avi)
{
  my $video_filename = $avi[$i];
  $video_filename =~ s/avi$/srt/;   # 'movie1.avi' -> 'movie1.srt'

  my $subtitle_filename = $srt[$i]; # 'film1.srt'
  rename($subtitle_filename, $video_filename); # 'film1.srt' -> 'movie1.srt'
}

Пожалуйста, посмотрите мои слайды для «Полевое руководство по параметрам командной строки Perl».

Слайд с `-e examples ': в Windows я предпочитаю q () и qq () вместо кавычек. Это позволяет мне использовать ту же однострочную версию Linux, заменяя только две внешние кавычки. Windows: perl -E "сказать q (Привет, мир)". Linux: perl -E'say q (Привет, мир) '

jfs 22.09.2008 00:15

Мертвая ссылка, что ...

dawg 22.11.2016 08:24

Зеркальная ссылка: web.archive.org/web/20120916013412/http://petdance.com/perl/‌…

xtreak 13.07.2017 11:00

В какой-то момент я обнаружил, что все, что я хотел бы сделать с Perl, что достаточно короткое, чтобы быть сделано в командной строке с помощью «perl -e», можно сделать лучше, проще и быстрее с помощью обычных функций оболочки Z без хлопот с цитированием. Например. приведенный выше пример можно сделать так:

srt=(*.srt); for foo in *.avi; mv $srt[1] ${foo:r}.srt && srt=($srt[2,-1])

glob-in-scalar-context действительно очень легко ошибиться; по возможности его следует избегать.

ysth 23.09.2008 11:27

Разве новая версия не рассинхронизируется при сбое MV?

ysth 23.09.2008 11:29

Что ж, сама идея этой штуки несколько нестабильна, поскольку предполагает, что для каждого .avi есть .srt и что оба, при сортировке по алфавиту, каждая пара avi / srt находится в одной и той же позиции в списках. Однако вы можете заменить && на; и обвяжите его фигурными скобками. ;)

jkramer 23.09.2008 21:17

Файлы журнала Squid. Они классные, правда? За исключением того, что по умолчанию в качестве поля времени у них есть секунды с эпохи. Вот однострочный файл, который читает из файла журнала squid и преобразует время в удобочитаемую дату:

perl -pe's/([\d.]+)/localtime /e;' access.log

С помощью небольшой настройки вы можете сделать так, чтобы он отображал только строки с интересующим вас ключевым словом. Следующие часы для stackoverflow.com получают доступ и печатают только эти строки с удобочитаемой датой. Чтобы сделать его более полезным, я даю ему вывод tail -f, чтобы я мог видеть доступы в реальном времени:

tail -f access.log | perl -ne's/([\d.]+)/localtime /e,print if /stackoverflow\.com/'

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

tail -F /var/log/squid/access.log | \
perl -ane 'BEGIN{$|++} $F[6] =~ m{\Qrad.live.com/ADSAdClient31.dll}
    && printf "%02d:%02d:%02d %15s %9d\n",
        sub{reverse @_[0..2]}->(localtime $F[0]), @F[2,4]'

Конвейер Perl начинает с установки для autoflush значения true, чтобы все, что было выполнено, немедленно распечатывалось. В противном случае вывод разбивается на части, и при заполнении буфера вывода получается пакет строк. Ключ -a разделяет каждую строку ввода на пробел и сохраняет результаты в массиве @F (функциональность основана на способности awk разбивать входные записи на переменные $ 1, $ 2, $ 3 ...).

Он проверяет, содержит ли седьмое поле в строке искомый URI (используя \ Q, чтобы избавить нас от боли, связанной с избеганием неинтересных метасимволов). Если совпадение найдено, он выводит время, IP-адрес источника и количество байтов, возвращаемых с удаленного сайта.

Время получается путем взятия времени эпохи в первом поле и использования «местного времени» для разбивки его на составляющие (час, минута, секунда, день, месяц, год). Он берет часть из первых трех возвращаемых элементов, секунд, минут и часов, и меняет порядок, чтобы получить часы, минуты и секунды. Он возвращается как трехэлементный массив вместе с фрагментом третьего (IP-адрес) и пятого (размер) из исходного массива @F. Эти пять аргументов передаются в sprintf, который форматирует результаты.

Вы можете не думать об этом как о Perl, но я неукоснительно использую подтверждать (это умная замена grep, написанная на Perl), и это позволяет мне редактировать, например, все мои тесты Perl, которые обращаются к определенной части нашего API:

vim $(ack --perl -l 'api/v1/episode' t)

В качестве примечания: если вы используете vim, вы можете запустить все тесты в буферах вашего редактора.

Для чего-то с более очевидным (хотя и простым) Perl мне нужно было знать, сколько тестовых программ использовали тестовые инструменты в каталоге t / lib / TestPM (я сократил команду для ясности).

ack $(ls t/lib/TestPM/|awk -F'.' '{print }'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

Обратите внимание, как «объединение» превращает результаты в регулярное выражение для передачи на подтверждение.

ссылка use.perl.org/~Ovid/journal/37470 не работает

Николай Мишин 20.04.2015 09:28

В ответ на Комбинация Vim / ack Овидия:

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

function vimify-eval; {
    if [[ ! -z "$BUFFER" ]]; then
        if [[ $BUFFER = 'ack'* ]]; then
            BUFFER = "$BUFFER -l"
        fi
        BUFFER = "vim  $($BUFFER)"
        zle accept-line
    fi
}

zle -N vim-eval-widget vimify-eval

bindkey '^P' vim-eval-widget

Это работает так: я ищу что-то с помощью ack, например ack some-pattern. Я смотрю на результаты и, если они мне нравятся, нажимаю стрелку вверх, чтобы снова получить строку подтверждения, а затем нажимаю Ctrl + P. Что происходит тогда, так это то, что оболочка Z добавляет и «-l» для перечисления имен файлов, только если команда начинается с «ack». Затем он помещает "$ (...)" вокруг команды и "vim" перед ней. Затем все выполняется.

Вот один из них, который мне пригодится при работе с коллекцией сжатых файлов журнала:

   open STATFILE, "zcat $logFile|" or die "Can't open zcat of $logFile" ;

Однострочность означает целую программу на одной строке, а не одну полезную строку программы.

ysth 23.09.2008 11:31

Я бы сам разделил это на 2 или более строк.

Brad Gilbert 03.10.2008 04:09

Я использую это довольно часто, чтобы быстро преобразовать времена эпох в полезную метку даты.

perl -l -e 'print scalar(localtime($ARGV[0]))'

Создайте псевдоним в своей оболочке:

alias e2d = "perl -le \"print scalar(localtime($ARGV[0]));\""

Затем передайте псевдониму номер эпохи.

echo 1219174516 | e2d

Многие программы и утилиты в Unix / Linux используют значения эпох для обозначения времени, поэтому для меня это оказалось бесценным.

Чтобы получить удобочитаемую метку времени из секунд эпохи, вы также можете использовать дату GNU со знаком @: date --date = @ 1219174516

Philip Durbin 19.09.2009 00:44

Фильтрует поток строф, разделенных пробелами (списки пар имя / значение), сортировка каждой строфы индивидуально:

perl -00 -ne 'print sort split /^/'

sort() поместит пустые строки в начало абзаца. Думаю, вы на самом деле имеете в виду следующее: perl -00 -ne '($ n, @a) = sort split / ^ /; print @a, $ n 'Оба однострочных сообщения завершатся ошибкой, если после последнего абзаца нет новой строки.

jfs 23.09.2008 21:20

Разверните все вкладки до пробелов: perl -pe'1while+s/\t/" "x(8-pos()%8)/e'

Конечно, это можно сделать с помощью: set et,: ret в Vim.

perl -pe'1 while + s / \ t / "" x (8- (pos)% 8) / e 'Скобки обязательны.

jfs 24.09.2008 01:16

Удалите дубликаты в переменной пути:

set path=(`echo $path | perl -e 'foreach(split(/ /,<>)){print $_," " unless $s{$_}++;}'`)

Что такое разделитель между путями в $ path? Смотрите мой ответ.

jfs 03.10.2008 03:07

Чаще всего я использую однострочник Perl - это калькулятор Perl.

perl -ple '$_=eval'

Если вы используете Perl 5.10, вы можете запустить perl -plE '$ _ = eval', чтобы включить функции 5.10.

Brad Gilbert 03.10.2008 04:08

@Dr Pepper

Удалите дубликаты буквальный в $PATH:

$ export PATH=$(perl -F: -ane'print join q/:/, grep { !$c{$_}++ } @F'<<<$PATH)

Печатайте уникальные чистые пути из переменной среды %PATH% (это не касается ../ и подобных, замените File::Spec->rel2abs на Cwd::realpath, если это желательно). Это не однострочный, чтобы быть более портативным:

#!/usr/bin/perl -w
use File::Spec; 

$, = "\n"; 
print grep { !$count{$_}++ } 
      map  { File::Spec->rel2abs($_) } 
      File::Spec->path;

Спасибо, что показали мне это, я искал для этого более короткий однострочник. В моей среде пробел является разделителем при использовании строчной буквы $ path. Лучше использовать верхний регистр $ PATH?

dr_pepper 03.10.2008 04:49

В моей оболочке (bash) $ path и $ PATH - разные переменные (имена чувствительны к регистру: $ a = 2; A = 3; echo $ (($ a * $ A)) Это печатает '6'.

jfs 03.10.2008 05:08

Дубликаты можно было удалить с помощью комбинации программ tr, sort, uniq, cut и пайпа.

jfs 03.10.2008 05:15

Но использование tr, sort и т. д. Изменяет порядок путей, что может вызвать нежелательные побочные эффекты.

dr_pepper 04.10.2008 19:16

В ZSH переменная path связана с переменной PATH, поэтому PATH всегда является элементами path, соединенными двоеточием, а path всегда является массивом, содержащим фрагменты PATH, разделенные столбцом. Чтобы сделать их уникальными, просто примените модификатор -U к одной из переменных: typeset -U PATH

jkramer 10.10.2008 15:08

Распространенная идиома использования find ... -exec rm {} \; для удаления набора файлов где-нибудь в дереве каталогов не особенно эффективна, поскольку она выполняет команду rm один раз для каждого найденного файла. Одна из моих привычек, рожденных в те дни, когда компьютеры были не такими быстрыми (dagnabbit!), - заменить множество вызовов rm одним вызовом perl:

find . -name '*.whatever' | perl -lne unlink

Часть командной строки perl читает список файлов, созданных * find, по одному в каждой строке, обрезает новую строку и удаляет файл с помощью встроенной в perl функции unlink(), которая принимает $_ в качестве аргумента, если явный аргумент не указан. . ($_ устанавливается для каждой строки ввода благодаря флагу -n.) (* В наши дни большинство команд find по умолчанию выполняет -print, поэтому я могу опустить эту часть.)

Мне нравится эта идиома не только из-за эффективности (возможно, менее важной в наши дни), но и из-за того, что в ней меньше сочетаний клавиш / неудобных клавиш, чем при вводе традиционной последовательности -exec rm {} \;. Это также позволяет избежать проблем с цитированием, вызванных именами файлов с пробелами, кавычками и т. д., Которых у меня много. (Более надежная версия может использовать опцию find-print0, а затем попросить perl читать записи с разделителями NULL вместо строк, но я обычно довольно уверен, что мои имена файлов не содержат встроенных символов новой строки.)

Я использую xargs для решения этой проблемы еще до того, как Perl засветился в глазах Ларри :-).

paxdiablo 13.10.2008 17:15

Справедливо, потому что это тема, связанная с Perl; но другая более надежная версия POSIX может использовать find ... -print0 | xargs -0 -- rm или GNU findutils: find ... --exec rm {} +⁽ʳᵉᶠ⁾

bufh 27.08.2020 15:26
Ответ принят как подходящий

Все однострочные ответы собраны в одном месте:

  • perl -pe's/([\d.]+)/localtime /e;' access.log

  • ack $(ls t/lib/TestPM/|awk -F'.' '{print }'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

  • perl -e'while(<*.avi>) { s/avi$/srt/; rename <*.srt>, $_ }'

  • find . -name '*.whatever' | perl -lne unlink

  • tail -F /var/log/squid/access.log | perl -ane 'BEGIN{$|++} $F[6] =~ m{\Qrad.live.com/ADSAdClient31.dll} && printf "%02d:%02d:%02d %15s %9d\n", sub{reverse @_[0..2]}->(localtime $F[0]), @F[2,4]'

  • export PATH=$(perl -F: -ane'print join q/:/, grep { !$c{$_}++ } @F'<<<$PATH)

  • alias e2d = "perl -le \"print scalar(localtime($ARGV[0]));\""

  • perl -ple '$_=eval'

  • perl -00 -ne 'print sort split /^/'

  • perl -pe'1while+s/\t/" "x(8-pos()%8)/e'

  • tail -f log | perl -ne '$s=time() unless $s; $n=time(); $d=$n-$s; if ($d>=2) { print qq ($. lines in last $d secs, rate ),$./$d,qq(\n); $. =0; $s=$n; }'

  • perl -MFile::Spec -e 'print join(qq(\n),File::Spec->path).qq(\n)'

См. Соответствующие ответы для их описания.

Удалите окончания строк MS-DOS.

perl -p -i -e 's/\r\n$/\n/' htdocs/*.asp

1. -i требует суффикса, например, -i.bak. 2. Не работает в Windows.

jfs 04.02.2009 14:38

Мне было интересно, как сделать Perl pie в Windows. Спасибо за совет.

JDrago 05.02.2009 04:00

Один из последних однострочников, нашедших место в моем ~ / bin:

perl -ne '$s=time() unless $s; $n=time(); $d=$n-$s; if ($d>=2) { print "$. lines in last $d secs, rate ",$./$d,"\n"; $. =0; $s=$n; }'

Вы можете использовать его против хвоста файла журнала, и он будет печатать скорость вывода строк.

Хотите знать, сколько посещений в секунду вы получаете на своих веб-серверах? хвост -f журнал | this_script.

Это миниатюрный просмотрщик каналов (pv) <ivarch.com/programs/pv.shtml>. Но ваш однострочник работает в Windows.

jfs 04.02.2009 14:52

Извлечение репутации Stack Overflow без необходимости открывать веб-страницу:

perl -nle "print '  Stack Overflow        ' .  . '  (no change)' if /\s{20,99}([0-9,]{3,6})</div>/;" "SO.html"  >> SOscores.txt

Предполагается, что страница пользователя уже загружена в файл SO.html. Для этого я использую wget. Обозначения здесь предназначены для командной строки Windows; он будет немного отличаться для Linux или Mac OS X. Вывод добавляется в текстовый файл.

Я использую его в сценарии BAT, чтобы автоматизировать выборку репутации на четырех сайтах семейства: Переполнение стека, сбой сервера, суперпользователь и переполнение мета-стека.

Получите удобочитаемый вывод от du, отсортированный по размеру:

perl -e '%h=map{/.\s/;7x(ord$&&10)+$`,$_}`du -h`;print@h{sort%h}'

У меня есть список тегов, с помощью которых я идентифицирую части текста. Главный список имеет формат:

text description {tag_label}

Важно, чтобы {tag_label} не дублировался. Итак, есть этот красивый простой скрипт:

perl -ne '($c) = $_ =~ /({.*?})/; print $c,"\n" '  | sort  | uniq -c | sort -d

Я знаю, что мог бы сделать все в оболочке или Perl, но это было первое, что пришло мне в голову.

perl -ne'$f{}++ while /({.*?})/g; END{ print "$f{$_} $_\n" for (sort {$f{$a} <=> $f{$b}} keys %f) }' . Вы правы, что для таких задач достаточно первой вещи. кстати, вы уверены, что в каждой строке может быть только один тег?

jfs 18.09.2009 23:24

Мне часто нужно видеть читаемую версию PATH во время написания сценария оболочки. Следующие однострочные символы печатают каждую запись пути в отдельной строке.

Со временем этот однострочник прошел несколько этапов:

Unix (версия 1):

perl -e 'print join("\n",split(":",$ENV{"PATH"}))."\n"'

Windows (версия 2):

perl -e "print join(qq(\n),split(';',$ENV{'PATH'})).qq(\n)"

Оба Unix / Windows (с использованием подсказки q / qq от @ j-f-sebastian) (версия 3):

perl -MFile::Spec -e 'print join(qq(\n), File::Spec->path).qq(\n)' # Unix
perl -MFile::Spec -e "print join(qq(\n), File::Spec->path).qq(\n)" # Windows

perl -MFile::Spec -E '$,=qq(\n); say File::Spec->path'

jfs 27.01.2011 19:04

perl -MFile::Spec::Functions -E '$,=qq(\n); say path'

jfs 27.01.2011 19:06

@ J.F. Себастьян: При запуске с -E я получаю Unrecognized switch: -E (-h will show valid options). как в Windows, так и в UNIX. Я использую perl v5.8.8 на обеих платформах.

Tim Lewis 27.01.2011 19:20

-E включает дополнительные функции, такие как say() от 5.10 (с 2007 г.).

jfs 27.01.2011 19:29

@ J.F. Себастьян: Спасибо, это полезный лакомый кусочек!

Tim Lewis 27.01.2011 19:35

Сетевые администраторы имеют тенденцию неправильно настраивать «адрес подсети» как «адрес хоста», особенно при использовании автоматического предложения Cisco ASDM. Этот простой однострочный сканер сканирует файлы конфигурации на предмет любых таких ошибок конфигурации.

неправильное использование: permit host 10.1.1.0

правильное использование: permit 10.1.1.0 255.255.255.0

perl -ne "print if /host ([\w\-\.]+){3}\.0 /" *.conf

Это было протестировано и использовалось в Windows, пожалуйста, предложите, следует ли его каким-либо образом изменить для правильного использования.

Часто мне приходилось преобразовывать табличные данные в файлы конфигурации. Например, поставщики сетевых кабелей предоставляют запись исправлений в формате Excel, и мы должны использовать эту информацию для создания файлов конфигурации. т.е.

Interface, Connect to, Vlan
Gi1/0/1, Desktop, 1286
Gi1/0/2, IP Phone, 1317

должно стать:

interface Gi1/0/1
 description Desktop
 switchport access vlan 1286

и так далее. Одна и та же задача повторно появляется в нескольких формах в различных задачах администрирования, где к табличным данным нужно добавить имя их поля и преобразовать в плоскую структуру. Я много раз видел, как некоторые администраторы баз данных тратят свои средства на подготовку своих операторов SQL из таблицы Excel. Этого можно добиться с помощью этого простого однострочника. Просто сохраните табличные данные в формате CSV с помощью вашего любимого инструмента для работы с электронными таблицами и запустите этот однострочный файл. Имена полей в строке заголовка добавляются к отдельным значениям ячеек, поэтому вам, возможно, придется отредактировать его в соответствии с вашими требованиями.

perl -F, -lane "if ($.==1) {@keys = @F} else{print @keys[$_].$F[$_] foreach(0..$#F)} " 

Предостережение: ни одно из имен или значений полей не должно содержать запятых. Возможно, это может быть доработано, чтобы улавливать такие исключения в одну строку, пожалуйста, улучшите это, если возможно.

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