Как стать автором
Обновить

Комментарии 45

НЛО прилетело и опубликовало эту надпись здесь
Не могу, кармы нема. Я тут новенький
А как же тот самый? :)
>perl -e '$??s:;s:s;;$?::s;;=]=>%-{
парсер — лох, схавал больше половины однострочника :/
вот он — тот самый:

cat «test… test… test...» | perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y; -/:-@[-`{-};`-{/" -;;s;;$_;see'



тем, кто будет запускать, советую сначала прочесть это siv.habrahabr.ru/blog/70649/
Старый патч…
Помнится его часто на убунте применяли те, у кого иксы падали.
НЛО прилетело и опубликовало эту надпись здесь
хорошо, что вы написали про «зачем то надо?» — а то я уже стал писать про rename+find+awk… ))

статья очень хорошая, респект.

вот за что я люблю могучий Perl…
в избранное, спасибо :)
perl заслуженно входит в клуб write-only языков
Смотря как писать.
LINE: while (defined($_ = )) {
print 1;
}

У вас тут Хабр съел <> — исправьте :)
Благодарю, исправил.
Задумался! :-) Я использовал -e только для проверки наличия модуля :-)
Всегда таскаю с собой утилитку для проверки наличия модулей и их версий:
#!/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)
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:

perl -E'say "hello"'

Теперь даже -l не нужен.
Я бы добавил ещё небольшое пояснение по поводу ключа -p, касательно его применения.
При использовании «скрипта» после | в «скрипт» (при -p) весь вывод предыдущей утилиты попадает разом (в STDIN), в то время, как без -p к каждой строке будет применён «скрипт» индивидуально (где «ввод» будет в $_) :)
Т.е. когда надо заменить переносы строк на табуляции, например, то используем
cat config.xml | perl -pe 'do{s/\n/\t/;print}while <>'
Я сделал тестовый пример:

Файл 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 ему не нужен. Поэтому просто укажите имя файла в виде последнего аргумента перлу, и «усё, шеф!» :)
НЛО прилетело и опубликовало эту надпись здесь
Все супер, спасибо автору, но это удивило

«Недавно мне понадобилось сделать 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() ?
перловый chmod поддерживает только цифры.
Совершенно верно, как и сишная функция chmod(), которую Perl вызывает. Поэтому, чтобы изменить текущие разрешения файла, нужно сначала их получить. Это удлиняет программу букв этак на 20, но это Perl way. Вот это ваш вариант:
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)
+1, Благодарю.
Примечание. Флаг -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 перлу не нужны.
Благодарю.
А зачем всё решать именно перлом?
А ссори, перл — это кроссплатформенно.
Ничего, что rmdir перловый удаляет только пустые директории?

Из перлдок
«Deletes the directory specified by FILENAME if that directory is empty»
а работают в операторе s/// переменные $1 и тп?
c ключами -pe не работают, в perlrun чота не нашел
Работают.
Если Вы делаете под Линукс, то либо используйте одинарные кавычки для кода, либо двойные, но тогда придётся экранировать доллары:

perl -pe 's/(.*)/bla-bla-$1/'

или

perl -pe "s/(.*)/bla-bla-\$1/"
ага, спасибо, не сообразил сначала, что bash тоже интерпретирует переменные =)
Работают.
Если Вы делаете под Линукс, то либо используйте одинарные кавычки для кода, либо двойные, но тогда придётся экранировать доллары:

perl -pe 's/(.*)/bla-bla-$1/'

или

perl -pe "s/(.*)/bla-bla-\$1/"

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации