単一行のPerlプログラム

はじめに



単一行のPerlプログラムについてお話します。 1行のPerlを習得すれば、多くの時間を節約できます(節約できます)。



この投稿の目的は、find、grep、awk、sedの代わりにPerlを使用する方法を示すことです。 投稿の最後に、なぜこれが必要なのかが書かれています。



まあ、まず最初に。





フラグ-e

このフラグを使用すると、コンソールで真珠コードを直接実行できます。この機能を使用して、何らかのテストコードをテストします。

16進数の0xFA23Bの10進数値を知りたいとします。

perl -e "print 0xFA23B"
      
      





ご注意 Windowsから単一行のパールバーコードを実行する場合、コードを二重引用符で囲む必要があります。

 perl -e "print 0xFA23B"
      
      



、Linux / Unixの場合、コードは二重引用符と一重引用符の両方にすることができますが、Unix / Linuxでは、二重引用符の場合は記号「$」でエスケープする必要があります
 perl -e "\$i = 0;print \$i"
      
      





ご注意 -eフラグの後、コードはすぐに続きます



フラグ-l

このフラグは、変数$ /および$ \を値 "\ n"で初期化します。

$ /変数は、入力フィールドの区切り文字を設定します。

$ \変数は、印刷コマンドの後に何が印刷されるかを指定します。



プログラム:

 perl -le "print 1"
      
      





以下と同等:

 BEGIN { $/ = "\n"; $\ = "\n"; } print 1;
      
      





したがって、最後にprint "\ n"と書く必要はありません。



フラグ-n

ここから楽しみが始まります。



次のコード:

 perl -ne 'print 1'
      
      





これと同等:

 LINE: while (defined($_ = <ARGV>)) { print 1; }
      
      





これはどこで使用できますか?

そしてここでは、たとえば、名前が数字で始まるファイルの名前に拡張子「bak」を追加する必要があります。



出来上がり:

 ls | perl -lne 'rename $_, "$_.bak" if /^\d+/'
      
      





そして、Windows用? お願い:

 dir /b | perl -lne "rename $_, \"$_.bak\" if /^\d+/"
      
      





結果のプログラムを見てみましょう:

 BEGIN { $/ = "\n"; $\ = "\n"; } LINE: while (defined($_ = <ARGV>)) { chomp $_; rename $_, "$_.bak" if /^\d+/; }
      
      





ムシャムシャ食べる$ _; -lフラグから取得: -nとともに、BEGIN {$ / = "\ n";だけでなく、chomp $ _;も追加します。 $ \ = "\ n"; }



フラグ-a

-aフラグを使用すると、Perlをawkとして使用できます。



次のコード:

 perl -nae "print 1"
      
      





と同等:

 LINE: while (defined($_ = <ARGV>)) { our(@F) = split(" ", $_, 0); print 1; }
      
      





つまり、各行はスペースに分割されて分割され、結果のフィールドは@F配列に入れられます。

フィールド区切り文字は、 -Fフラグを使用して変更できます。



/ etc / passwdファイルからホームディレクトリを含むユーザー名を出力するとします。

 less /etc/passwd | perl -F: -nlae 'print "$F[0]:$F[4]"'
      
      





また、たとえばWindowsの場合、2009年9月に最後に変更したフォルダー内のファイルの名前を調べたいと思います。

 dir /TW | perl -nale "print $F[$#F] if $F[0] =~ /\.09\.2009/"
      
      





-Pフラグ

また、このフラグは-nが「print $ _」で別のcontinueブロックを追加するだけです。



次のコード:

 perl -pe "print 1"
      
      





と同等:

 LINE: while (defined($_ = <ARGV>)) { print 1; } continue { print $_; }
      
      





ファイル/ etc / passwdを出力し、同時に3を6に置き換えたとします。



このコードの代わりに:

 less /etc/passwd | perl -ne "s/3/6/;print \$_"
      
      





私たちは書くことができます:

 less /etc/passwd | perl -pe "s/3/6/"
      
      





フラグ-i

iフラグを使用すると、ファイルを変更できます。



次のプログラム:

 perl -i.bak -pe "s/foo/bar/"
      
      





これと同等:

 BEGIN { $^I = ".bak"; } LINE: while (defined($_ = <ARGV>)) { s/foo/bar/; } continue { print $_; }
      
      





これはこれと同等です:

 $extension = '.bak'; LINE: while (<>) { if ($ARGV ne $oldargv) { if ($extension !~ /\*/) { $backup = $ARGV . $extension; } else { ($backup = $extension) =~ s/\*/$ARGV/g; } rename($ARGV, $backup); open(ARGVOUT, ">$ARGV"); select(ARGVOUT); $oldargv = $ARGV; } s/foo/bar/; } continue { print; # this prints to original filename } select(STDOUT);
      
      





perl -i.bak -pe“ code” <file name>という行が呼び出されたときに何が起こるかを簡単に説明します。 たとえば、次のように呼び出します。

 perl -i.bak -pe "s/foo/bar/" test.txt
      
      





test.txtファイルの名前がtest.txt.bakファイルに変更され、新しいtest.txtファイルが作成されます。 次に、ソースファイルの各行で、fooがbarに置き換えられ、新しいtest.txtファイルに書き込まれます(明らかに、ファイルの名前が変更された場合でも、その行にアクセスできますか?)



ファイル内の\ r \ nを\ nに置き換えたいとします:

 perl -i.bak -pe 's/\r\n/\n/' test.txt
      
      





このコードの結果、2つのファイルが取得されます。1つはソースのコピーであるtest.txt.bak、もう1つは\ r \ nが\ nに置き換えられたtest.txtです。



ご注意 上記のプログラムを詳細に見ると($ extension = '.bak'; ...)、perl -ibak_ * ...のように呼び出すと、バックアップファイルが「bak_test.txt」と呼ばれることがわかります。パラメータiの値にアスタリスクが含まれている場合、この値は拡張子ではなくテンプレートと見なされます。アスタリスクはファイル名を示します。



フラグ-M



-Mフラグを使用すると、モジュールを接続できます



たとえば、私はCGIモジュールがどこにあるかを知りたい:



Windowsの場合:

 perl -MCGI -le "print $INC{'CGI.pm'}"
      
      





Linuxの場合:

 perl -MCGI -le "print \$INC{'CGI.pm'}"
      
      





最近、拡張子「.cgi」を持つすべてのファイルに対してchmod a + xを作成する必要がありました。

しかし、サーバー上で何らかの理由でchmodの-Rフラグが機能しなかったため、これが私がしたことです。

 perl -MFile::Find -e 'finddepth(sub {print $File::Find::name . "\n"}, "."})' | grep -P '\.cgi$' | perl -nle '`chmod a+x $_`'
      
      





このコードでは、「perl -MFile :: Find -e 'finddepth(sub {print $ File :: Find :: name。„ \ N“}、”。 "})'」 'File:Findモジュールのfinddepth関数を呼び出しました。現在のディレクトリを再帰的にバイパスし、完全なファイルパスを表示しました。



次に、グリップを使用して、「。cgi」で終わるファイルのみを取りました(-Pはパール大麦の正規表現が使用されることを意味します)、次のプログラム「perl -nle '' chmod a + x $ _``」で実行権を作りました見つかったファイル。



このコードは次のように書くこともできますが:

 perl -MFile::Find -e 'finddepth(sub {$n = $File::Find::name;`chmod a+x $n` if $n =~ /\.cgi$/}, ".")'
      
      





$ _に「\ n」のないファイル名が含まれないように、-lフラグを使用する必要があることに注意してください。



しかし、プラグインパッケージからメインパッケージにいくつかの変数またはルーチンを接続する必要がある場合はどうでしょうか。

次に、書く必要があります:

 perl -MModule=foo,bar -e '...';
      
      





または

 perl '-Mmodule qw(foo bar)' -e '...';
      
      





BEGINおよびEND



awkと同様に、最初と最後に発生する必要があるアクションにBEGINとENDを使用できます。

 perl -e 'BEGIN{< >};<>;END{ }';
      
      





たとえば、レポートの最初と最後に40個の「=」記号で構成される線を描画します。

 dir /b | perl -pe "sub line {print '=' x 40 . \"\n\"};BEGIN{line();};END{line()}"
      
      





デバッグする



単一行のプログラムをデバッグするには、B :: Deparseモジュールを接続する必要があります。



実行する場合:

 perl -MO=Deparse -ne "print 1"
      
      





出力が得られます:

 LINE: while (defined($_ = <ARGV>)) { print 1; } -e syntax OK
      
      





B :: Deparseモジュールは、「-MO = Deparse」のように接続する必要がありますが、「-MB :: Deparse」のように接続する必要はありません。 どうやらこれは、プログラムでメソッドを使用するだけでなく、このモジュールを使用してプログラムのソースコードを表示することを明確に定義するために行われたようです。



これは、B :: Deparseモジュールが通常のモジュールとして使用される方法です。コード出力はありません。

 perl -MB::Deparse -e "print 1"
      
      





上記の例では、MO = Deparseを使用してプログラムコードを出力しました。

単一行プログラムの例



ファイルの行数を出力します(Unix wc -lのアナログ)

 perl -ne '}{ print $.' abc.txt
      
      





同等のプログラム:

 LINE: while (defined($_ = <ARGV>)) { (); } { print $.; }
      
      





ここでは、トリッキーなトリック「} {」が使用されています。 私たち自身がサイクルを閉じました。



バイナリ出力

 perl -e "printf '%b', shift" 200
      
      





ファイル内の\ r \ nを\ nで置き換える

 perl -i.bak -pe 's/\r\n/\n/' file.txt
      
      





ご注意 何らかの理由で、Windowsでは同様のコードは機能しません:それは永続的に\ r \ nを追加し、binmode ARGVを行いました、

binmode $ ARGV、binmode * ARG {FILEHANDLE}、しかし何も役に立たなかったので、さらに戦います。 Windowsで\ r \ nを\ nに置き換える方法を書いていただければ幸いです。



IPアドレスを数字からドットに変換する:

 perl -e "print unpack('N', pack('C4', split /\./, shift))" 127.0.0.1
      
      





現在のフォルダーとそのサブフォルダー内の.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 $_\");"
      
      





16進IPアドレス出力

 perl -e "printf '%02x' x 4, split /\./, shift" 127.0.0.1
      
      





ファイルの先頭に「#!/ Usr / bin / perl」という行を追加します

 perl -i.bak -pe "print \"#!/usr/bin/perl\n\" if $. == 1" abc.pl
      
      





Linux / Unixの場合:

 perl -i.bak -pe 'print "#!/usr/bin/perl\n" if $. == 1' abc.pl
      
      





なぜこれが必要なのですか?



約束したように、なぜこれがすべて必要なのかを書きます。 find、awk、grep、sedがあると言えますが、なぜ単一行のPerlなのでしょうか?



まず、Windowsでは、デフォルトでgrepとawkはありません。 はい、もちろんgrepを使用して行を選択する方が高速ですが、たとえばファイルの名前を変更するなど、もう少し行う必要がある場合はどうでしょうか。 結局、あると言う、そうです。 それでは、単線真珠を守るために何と言いますか?



そしてここに何があります:



まず、Perlでプログラミングする場合、Perlを非常によく覚えているので、人を見ずにすぐに単一行のプログラムの作成を開始できます。 (ただし、最初は少し珍しいかもしれませんが、参加すると簡単になります)



第二に、Perlを使用すると便利です。 たとえば、Perlの力でawkの類似物(-aフラグを参照)が必要な場合(たとえば、単一行プログラムでpack、unpack、またはPerl正規表現を使用したい)



第三に

Perlは強力な言語です。 単一行のperlプログラムは、コマンドラインのみの通常のPerlプログラムです。 したがって、単一行の真珠プログラムはさまざまなタスクに使用できます! (ただし、長い単一行のプログラムを作成しない方が良いと思います。通常の真珠のスクリプトを作成する方が良いでしょう)。



おわりに



grep、find、sed、またはawkを拒否することを強くお勧めするだけだとは思わないでください。 私は促しません! 私自身もgrepを使い続けています。 Perlでプログラミングする人にとって便利な「1行の真珠」として別の便利なツールについてお話ししたかったのは、1)人を読む必要がない(すでにすべてを覚えている)、2)Perlの力が使用されているから



ご清聴ありがとうございました。 興味がある人はここに送ってください:



perldoc.perl.org/perlrun.html-perldoc、すべてのフラグの説明。

sial.org/howto/perl/one-liner-さまざまな例



私はあなたに単語を使って真珠の単一行プログラムをグーグルにすることを勧めます:ワンライナー



更新:

Windowsで\ r \ nを\ nに置き換えるには、次のように書くだけです。

 perl -i.bak -ple "s/\r|\n//g;binmode ARGVOUT" file.txt
      
      





アントン・シェルビニンを尊重する



更新:

AntonShcherbininのコードに追加された「 s / \ r | \ n // g; 」、それ以外の場合はLinuxでbinmodeをロールしないだけで、このコードは普遍的です:WindowsとLinuxの両方で動作します。



アップデート(2012年8月26日):

<source lang = "Perl"> </ source>タグの下のコード例を書き直しました



All Articles