編輯/整理:523066680@163.com
首發:[連載]Perl 命令行一句話代碼,翻譯+整理
序:內容取自 《Perl One-Liners》,注意該教程中示例的 ' 符號(單引號)在windows 中應改為雙引號,否則不會奏效。我在翻譯和摘錄的代碼中也會改用雙引號
備注:
- 不做全文翻譯,盡量簡明
- 假設看官已經有正則表達式基礎
- 環境:Win7, Strawberry Perl 5.24 Portable Edition
Chapter 1 - Perl ONE-LINERS
第一個示例,全局將文件中的 you 替換為 me:
perl -pi -e "s/you/me/g" file
/g 表示全局替換
-e 參數允許執行 Perl 代碼
-p 參數確保處理文本的每一行並且將處理后的結果打印出來
-i 參數將修改的結果應用到文件中(所以看不到 -p 打印的內容了)
-i[extension] edit <> files in place (makes backup if extension supplied)
注意,實際測試 -i 參數必須提供擴展名以備份文件,否則提示:Can't do inplace edit without backup.
perl -pi.bak -e "s/you/me/g" file
處理多個文件:
perl -pi.bak -e "s/you/me/g" file1 file2 file3
僅處理含有"we"的行:
perl -pi.bak -e "s/you/me/g if /we/" file
打印文件中重復出現的行:
perl -ne "print if $a{$_}++" file
$_ 表示當前遍歷的行的內容
-n 表示遍歷所有行(類似 -p 但不負責打印結果)
執行后將自動建立字典 %a,當 $_ 對應的值第一次出現的時候,$a{$_} 還是 undef(同0),+1在下次生效。再次出現時為1,打印輸出,以此類推。
添加並打印行號:
perl -ne "print \"$. $_\"" file
在 Perl 中,$. 是一個特殊變量,表示當前行數。這個例子也可以改用 -p
perl -pe "$_ = \"$. $_\"" file
帶行號,但僅顯示重復行
perl -ne "print \"$. $_\" if $a{$_}++" f.txt
借用 List::Util 模塊統計每行中出現的數字的和
perl -MList::Util=sum -alne 'print sum @F' f.txt
說明:
-MList::Util 導入 List::Util 模塊
=sum 表示導入 List::Util 的 sum 函數
-a 參數,自動按空格划分行的內容並保存到 @F,使單詞、數字獨立出來
注 -F/pattern/ 參數可指定其他划分規則
-l 參數確保每一次輸出都換行,省了手動 "\n"
讓時間回退到 1299 天前:
perl -MPOSIX -le "@t = localtime; $t[3] -= 1299; print scalar localtime mktime @t"
實際時間:
Wed Apr 26 19:31:22 2017
輸出:
Sat Oct 5 19:31:22 2013
這個過程實際就是 用 @t 獲取 localtime 的返回結果(數組環境),將日期減1299(在數組成員中會變成負數),再使用 mktime 將其封裝,返回給 localtime,再用標量環境打印 localtime 的返回值
如何生成8位隨機字符密碼?map 走起:
perl -le "print map { ('a'..'z')[rand 26] } 1..8"
1..8 產生數組數字從 1-8,關鍵是產生8次循環
('a'..'z') 產生數組元素a-z,而 [rand 26] 隨機產生數組下標,也就是隨機選取字母
map 返回每一次循環的處理結果
要我寫的話可能會用 grep ,逐個 print
perl -e "grep { print (('a'..'z')[rand 26]) } (1..8)"
發現 print ('a'..'z')[rand 26] 會提示語法問題,必須外加括號。
累計文本中每行的首列數字的和
perl -lane "$sum += $F[0]; END { print $sum }" f.txt
END {} 定義了一個代碼塊,該代碼塊在腳本結束時運行
如果對 perl 的任一項參數有疑惑,可以參考
perldoc perlrun
其他參考
perldoc perlvar - 關於 Perl 的特殊變量
perldoc perlop - 操作符
perldoc perlfunc - 函數
Chapter 2 - 換行和間隔符
在每行的末尾增加空白行
perl -pe "$\=\"\n\"" f.txt
之前對 -p 和 -e 參數做過簡要的說明,以上代碼相當於:
while (<>) {
$\ = "\n";
} continue {
print or die "-p failed: $!\n";
}
構成
-p 參數建立 while (<>) {} continue { print } 循環結構
在 while 循環內默認用 $_ 存儲當前讀入的行,而 print 的缺省參數為 $_
-e "代碼" 對應 while 循環內的代碼。
continue 語句塊在 while 的每次循環末尾繼續執行,
特點是 continue {} 的代碼不會因為 next 而跳過
特殊變量 $\ 相當於 AWK 中的 ORS 變量 (Output Record S eparator) 。
$\ 的內容將自動追加到 $_ 的末尾。循環地為 $\ 賦相同的值是不必要的,
將其放在 BEGIN 代碼塊可以節省開銷(BEGIN代碼塊優先執行):
perl -pe "BEGIN { $\=\"\n\" } " f.txt
相當於:
BEGIN { $\ = "\n" }
while (<>) {
} continue {
print or die "-p failed: $!\n";
}
其他方案
通過 "." 操作符添加換行:
perl -pe "$_ .= \"\n\"" f.txt
或者使用s///正則替換:
perl -pe 's/$/\n/' f.txt
甚至可以利用 say 操作符的特性(Perl 5.10 或以上):
perl -nE 'say' f.txt
-E 參數允許打開所有 Perl 的可選特性(為了支持 say 操作符)
-n 參數類似 -p ,遍歷所有讀入的行但不主動 print(前面介紹過了)
say 操作符類似 print,但 say 總是在每行的末尾添加 "\n"
最后,別忘了多用 perldoc, 執行 perldoc perlrun 查看perl命令行參數的詳細說明
換行加倍,空行除外
perl -pe "$_ .= \"\n\" unless /^$/" f.txt
unless 在 perl 中是 if not 的意思
/^$/ 表示行的開頭和末尾之間沒有其他字符
也可以用 \S 篩選:
perl -pe "$_ .= \"\n\" if /\S/" f.txt
\s 代表一系列空白符號
\S 表示空白以外的字符
如果一行中包含空給以外的字符,則追加 \n
三倍換行符
相信各位已經能舉一反三,不解釋了(后面的命令行示例省去文件名部分)
perl -pe "$\ = \"\n\n\""
perl -pe "$_ .= \"\n\n\""
perl -pe "s/$/\n\n/"
N倍換行符
Perl 使用 "字符"x數字 的方式對字符串翻倍疊加,例如7個換行符:"\n"x7
在每行之前添加空行
使用正則替換向文件開頭插入\n:
perl -pe 's/^/\n/'
刪除空白行
perl -ne 'print unless /^$/'
由於這里要自己判斷(篩選)輸出,所以使用 -n 而非 -p
