Комментарии 45
НЛО прилетело и опубликовало эту надпись здесь
А как же тот самый? :)
>perl -e '$??s:;s:s;;$?::s;;=]=>%-{
>perl -e '$??s:;s:s;;$?::s;;=]=>%-{
парсер — лох, схавал больше половины однострочника :/
вот он — тот самый:
тем, кто будет запускать, советую сначала прочесть это siv.habrahabr.ru/blog/70649/
cat «test… test… test...» | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y; -/:-@[-`{-};`-{/" -;;s;;$_;see'
тем, кто будет запускать, советую сначала прочесть это siv.habrahabr.ru/blog/70649/
НЛО прилетело и опубликовало эту надпись здесь
ну и конечно, это должен прочесть каждый — www.linux.org.ru/view-message.jsp?msgid=392747&page=-1
:)
:)
хорошо, что вы написали про «зачем то надо?» — а то я уже стал писать про rename+find+awk… ))
статья очень хорошая, респект.
статья очень хорошая, респект.
вот за что я люблю могучий Perl…
в избранное, спасибо :)
в избранное, спасибо :)
perl заслуженно входит в клуб write-only языков
LINE: while (defined($_ = )) { print 1; }
У вас тут Хабр съел <> — исправьте :)
Задумался! :-) Я использовал -e только для проверки наличия модуля :-)
Всегда таскаю с собой утилитку для проверки наличия модулей и их версий:
Называю её mver. Удобней, чем набирать каждый раз perl -MModule -e1
#!/usr/bin/env perl my $module = shift; my $is_loaded = eval "require $module; $module->import; 1"; unless($is_loaded) { print "$module was not loaded: $@" } else { print $module->VERSION || 'Loaded, but no $VERSION defined' } print $/
Называю её mver. Удобней, чем набирать каждый раз perl -MModule -e1
Сделал утилитку для поиска файлов регулярным выражением (для Никсов говорят find поддерживает регулярки)
rs.bat (rs — regexp search)
Прописал в системные переменные путь к ней.
теперь вызываю её так:
rs /<регулярное выражение>/<флаги>
пример: rs /\.pl$/
rs.bat (rs — regexp search)
perl -MFile::Find -MCwd -le "$path = getcwd;finddepth(sub {print $File::Find::name if %1}, $path)"
Прописал в системные переменные путь к ней.
теперь вызываю её так:
rs /<регулярное выражение>/<флаги>
пример: rs /\.pl$/
Буду благодарен вам, если напишите как заменить \r\n на \n в Винде.Если мне требуется гарантированно разграничить \r\n и \n, я предпочитаю писать явным образом \x0d и \x0a вместо \r и \n.
Еще стоит отметить, что в 5.10 появился отличный ключик -E, который включает директиву features:
Теперь даже -l не нужен.
perl -E'say "hello"'
Теперь даже -l не нужен.
Я бы добавил ещё небольшое пояснение по поводу ключа -p, касательно его применения.
При использовании «скрипта» после | в «скрипт» (при -p) весь вывод предыдущей утилиты попадает разом (в STDIN), в то время, как без -p к каждой строке будет применён «скрипт» индивидуально (где «ввод» будет в $_) :)
Т.е. когда надо заменить переносы строк на табуляции, например, то используем
cat config.xml | perl -pe 'do{s/\n/\t/;print}while <>'
При использовании «скрипта» после | в «скрипт» (при -p) весь вывод предыдущей утилиты попадает разом (в STDIN), в то время, как без -p к каждой строке будет применён «скрипт» индивидуально (где «ввод» будет в $_) :)
Т.е. когда надо заменить переносы строк на табуляции, например, то используем
cat config.xml | perl -pe 'do{s/\n/\t/;print}while <>'
Я сделал тестовый пример:
Файл abc.txt такого содержания.
потом запустил
Мне вывело только "#!/usr/bin/perl". Так что Вы уверены, насчёт Вашего высказывания?
Файл abc.txt такого содержания.
#!/usr/bin/perl
#!/usr/bin/perl
Xывафfdasdfasfd
asdfasfda
sfasdfasfd
asfdasdfa
sdfasdfasfd
потом запустил
type abc.txt | perl -pe "print $_;last"
Мне вывело только "#!/usr/bin/perl". Так что Вы уверены, насчёт Вашего высказывания?
Т.е. когда надо заменить переносы строк на табуляции, например, то используем
cat config.xml | perl -pe 'do{s/\n/\t/;print}while <>'
Вы, видимо, не понимаете самой сути ключа -p. -p означает «print». Т. е. этот ключ избавляет вас от необходимости печатать строку после того, как вы её изменили, т. к. печать будет сделана автоматически. Кроме того, это дополнение к -n, т. е. помимо вывода строки этот ключ организует цикл по всем строкам входного файла, а ваш «скрипт» является лишь телом этого цикла. Т. е. при использовании -p в 99.9% случаев никаких while <> в явном виде писать не надо.
В итоге, чтобы решить вашу задачу (заменить \n на \t в файле config.xml ) с помощью Perl, нужно сказать
perl -wpe 'tr/\n/\t/' config.xml
И никаких while, никаких print: их Perl делает за вас.
Да, я чуть не забыл сказать, что писать
cat file |
тоже не нужно (и это плохая привычка). Perl (и любая правильная POSIX-утилита) замечательно умеет читать файл сам, помощник в виде cat ему не нужен. Поэтому просто укажите имя файла в виде последнего аргумента перлу, и «усё, шеф!» :)
Советую ознакомится с однострочниками Бена Окопника, написанными в детективном стиле:
gazette.linux.ru.net/lg84/okopnik.html
gazette.linux.ru.net/lg85/okopnik.html
gazette.linux.ru.net/lg86/okopnik.html
gazette.linux.ru.net/lg87/okopnik.html
gazette.linux.ru.net/lg88/okopnik.html
gazette.linux.ru.net/lg89/okopnik.html
gazette.linux.ru.net/lg84/okopnik.html
gazette.linux.ru.net/lg85/okopnik.html
gazette.linux.ru.net/lg86/okopnik.html
gazette.linux.ru.net/lg87/okopnik.html
gazette.linux.ru.net/lg88/okopnik.html
gazette.linux.ru.net/lg89/okopnik.html
Все супер, спасибо автору, но это удивило
«Недавно мне понадобилось сделать chmod a+x всем файлам с расширением ».cgi",
но на сервере флаг -R для chmod почему-то не работал, так вот что я сделал, что-то подобное:
perl -MFile::Find -e 'finddepth(sub {print $File::Find::name. "\n"}, "."})' | grep -P '\.cgi$' | perl -nle '`chmod a+x $_`'"
Можно же было find. -name *.cgi | perl -nle '`chmod a+x $_`'"
Я прекрасно понимаю, что идея топика — показать мощь однострочек перла, но не удержался, извините :)
«Недавно мне понадобилось сделать chmod a+x всем файлам с расширением ».cgi",
но на сервере флаг -R для chmod почему-то не работал, так вот что я сделал, что-то подобное:
perl -MFile::Find -e 'finddepth(sub {print $File::Find::name. "\n"}, "."})' | grep -P '\.cgi$' | perl -nle '`chmod a+x $_`'"
Можно же было find. -name *.cgi | perl -nle '`chmod a+x $_`'"
Я прекрасно понимаю, что идея топика — показать мощь однострочек перла, но не удержался, извините :)
find. -name '*.cgi' -type f -exec chmod a+x '{}' \;
:-), просто я с find пока не очень дружу. Благодарю.
В данном случае применение File::Find, далеко не самого очевидного модуля, скорее оттолкнёт людей от Perl, чем приблизит к нему. Ваш вариант лучше, чем у автора статьи, но всё равно значительно менее нагляден и эффективен, чем естественное
find . -name \*.cgi | xargs chmod +x
(если есть шанс «напороться» на файлы с пробелами в имени, нужно добавить -print0 для find и -0 для xargs). Если, скажем, на диске окажется 150 .cgi-файлов, то ваш вариант запустит 150 процессов chmod, а последний вариант — только 1.
Кроме того, раз уж вы используете Perl, то почему бы не использовать перловую функцию chmod() ?
find . -name \*.cgi | xargs chmod +x
(если есть шанс «напороться» на файлы с пробелами в имени, нужно добавить -print0 для find и -0 для xargs). Если, скажем, на диске окажется 150 .cgi-файлов, то ваш вариант запустит 150 процессов chmod, а последний вариант — только 1.
Кроме того, раз уж вы используете Perl, то почему бы не использовать перловую функцию chmod() ?
перловый chmod поддерживает только цифры.
Совершенно верно, как и сишная функция chmod(), которую Perl вызывает. Поэтому, чтобы изменить текущие разрешения файла, нужно сначала их получить. Это удлиняет программу букв этак на 20, но это Perl way. Вот это ваш вариант:
perl -MFile::Find -we 'find(sub {/\.cgi$/ and chmod((stat)[2] || 0111)}, ".")'
perl -MFile::Find -e 'finddepth(sub {$n = $File::Find::name;`chmod a+x $n` if $n =~ /\.cgi$/}, ".")'А вот вариант на Perl:
perl -MFile::Find -we 'find(sub {/\.cgi$/ and chmod((stat)[2] || 0111)}, ".")'
можно было и еще проще :) через -exec
Да это понятно. Но я тут хотел показать применение перла вместе с шеллом :)
perl -i.bak -pe 's/\r\n/\n/' file.txt
Примечание. Почему-то подобный код не работает в Винде: она упорно добавляет \r\n, я делал binmode ARGV,
binmode $ARGV, binmode *ARG{FILEHANDLE}, но ничего не помогало, буду биться дальше. Буду благодарен вам, если напишите как заменить \r\n на \n в Винде.
«Когда вы совсем отчаялись, перепробовали все варианты, но ничего не помогает, прочтите, наконец, инструкцию» ;-)
perl -i.bak -pe «binmode ARGVOUT» file.txt
(Хабр заменил прямые кавычки на кавычки «ёлочкой», не знаю, как его отучить)
Ещё раз подчеркну, что это код для Windows. Никакие замены \r\n на \n в явном виде не нужны, потому что именно это делает сама Windows, читая из файла file.txt. Нужно лишь попросить Windows не делать обратного преобразования при записи в выходной файл, сказав binmode ARGVOUT.
Ирония состоит в том, что вы сами, OlegTar, послали всех читать perldoc perlrun (искать ARGVOUT), где и содержится ответ :o)
Примечание. Флаг -e должен стоять последним среди всех флагов.
perl -e «print 'That';» -e «print 'is not';» -e «print 'true'» -wl
Флаг -e может стоять каким угодно среди всех флагов, но если вы неправильно пользуетесь объединением ключей и, имея в виду
perl -e 'print 1' -w -l
, пишете
perl -ewl '-print 1'
То у вас, действительно, ничего не получится, т. к. wl будут интерпретированы как текст перловой программы, которую нужно выполнить, а не как ключи для самого perl. Но это не значит, что -e должен быть последним. Пишите perl -e 'program' -f -o -o, и всё будет в ажуре.
Удаление папок .svn в текущей папке и её подпапках (рекурсивно)
perl -MFile::Find -MCwd -e '$path = getcwd;finddepth(sub {print $File::Find::name."\n"}, "$path")' | grep '\.svn$' | perl -ne 'system(«rm -rf $_»)';
тоже самое для Windows:
perl -MFile::Find -e «finddepth(sub{ print $File::Find::name. \»\n\"; }, '.')" | perl -ne «print if /.svn$/» | perl -pe «s|/|\\|g» | perl -ne «system(\»rd /s /q $_\");"
Раз уж вы ратуете за Perl way, то стОит использовать Perl «на полную катушку», а не как замену find (в случае Unix) или несколько perl как замену find, grep, sed и запускалку rd (в случае Windows):
perl -MFile::Find -we 'finddepth(sub {$File::Find::name =~ m"/\.svn(/|$)" and -f()? unlink(): rmdir()}, ".")'
Это будет работать и в Unix, и в Windows (хотя в Windows, конечно, нужно поменять двойные кавычки на апострофы, и наоборот). И никакие костыли в виде grep, find и rm/rmdir перлу не нужны.
а работают в операторе s/// переменные $1 и тп?
c ключами -pe не работают, в perlrun чота не нашел
c ключами -pe не работают, в perlrun чота не нашел
Работают.
Если Вы делаете под Линукс, то либо используйте одинарные кавычки для кода, либо двойные, но тогда придётся экранировать доллары:
или
Если Вы делаете под Линукс, то либо используйте одинарные кавычки для кода, либо двойные, но тогда придётся экранировать доллары:
perl -pe 's/(.*)/bla-bla-$1/'
или
perl -pe "s/(.*)/bla-bla-\$1/"
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Однострочные программы на Perl