はじめに
単一行の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>タグの下のコード例を書き直しました