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

Однострочный должен:

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

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

Ответы

Ответ 1

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

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

  • ack $(ls t/lib/TestPM/|awk -F'.' '{print $1}'|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)'

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

Ответ 3

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

Переименуйте все *.srt(файлы с субтитрами) в соответствии с *.avi(файлы с видео).

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

CAVEAT: Порядок сортировки исходных имен файлов видео и субтитров должен быть одинаковым.

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

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'
}

Ответ 4

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

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

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

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

Ответ 5

Вы можете не думать об этом как о Perl, но я использую ack религиозно (это умная замена 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 $1}'|xargs perl -e 'print join "|" => @ARGV') aggtests/ t -l

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

Ответ 6

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

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

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

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

Ответ 7

В одном слое Perl я использую больше всего калькулятор Perl

perl -ple '$_=eval'

Ответ 8

Одна из самых больших полосчатых свиней в $work - это загрузка веб-рекламы, поэтому я смотрю на низко висящие фрукты, ожидающие их выбора. Я избавился от рекламы 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...).

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

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

Ответ 9

@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;

Ответ 10

В ответ на комбинацию Ovids vim/ack:

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

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. Затем происходит то, что ZSH добавляет и "-l" для перечисления имен файлов, только если команда начинается с "ack". Затем он помещает "$ (...)" вокруг команды и "vim" перед ней. Затем выполняется все это.

Ответ 11

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

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

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

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

Затем переместите номер псевдонима в псевдоним.

echo 1219174516 | e2d

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

Ответ 12

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

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

Ответ 13

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

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

Ответ 14

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

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

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

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

Ответ 15

Мне часто нужно видеть читаемую версию 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

Ответ 16

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

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

Ответ 17

Один из самых последних одностроек, который получил место в моем ~/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; }'

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

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

Ответ 18

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

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

Ответ 19

Сетевые администраторы имеют тенденцию неправильно настраивать "адрес подсети" как "адрес хоста", особенно при использовании автоматического предложения 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, пожалуйста, предложите, чтобы он был каким-либо образом изменен для правильного использования.

Ответ 20

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

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

Ответ 21

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

text description {tag_label}

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

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

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

Ответ 22

Часто мне приходилось преобразовывать табличные данные в файлы конфигурации. Например, поставщики сетевых кабелей предоставляют исправление в формате 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

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

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

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

Ответ 23

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

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

Ответ 24

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

for foo in *.avi; mv *.srt ${foo:r}.srt

UPDATE

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

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