[英]How can I use perl to delete files matching a regex
由於Makefile
錯誤,我的 git 存儲庫中有一些假文件......
$ ls
=0.1.1 =4.8.0 LICENSE
=0.5.3 =5.2.0 Makefile
=0.6.1 =7.1.0 pyproject.toml
=0.6.1, all_commands.txt README_git_workflow.md
=0.8.1 CHANGES.md README.md
=1.2.0 ciscoconfparse/ requirements.txt
=1.7.0 configs/ sphinx-doc/
=2.0 CONTRIBUTING.md tests/
=2.2.0 deploy_docs.py tutorial/
=22.2.0 dev_tools/ utils/
=22.8.0 do.py
=2.7.0 examples/
$
我試過了,但似乎可能有一些更有效的方法來完成這個任務......
# glob "*" will list all files globbed against "*"
foreach my $filename (grep { /\W\d+\.\d+/ } glob "*") {
my $cmd1 = "rm $filename";
`$cmd1`;
}
perl
解決方案來刪除與此/\W\d+\.\d+/
正則表達式匹配的文件:/\W\d+\.\d+/(例如文件名:'=0.1.1') ?獲取更廣泛的文件集,然后過濾任何你想要的
my @files_to_del = grep { /^\W[0-9]+\.[0-9]+/ and not -d } glob "$dir/*";
我添加了一個錨點 ( ^
),以便正則表達式只能匹配以該模式開頭的字符串,否則這可能會破壞預期以外的文件。 重新考慮您到底需要什么。
總而言之(或者看下面的一行† )
use warnings;
use strict;
use feature 'say';
use File::Glob ':bsd_glob'; # for better glob()
use Cwd qw(cwd); # current-working-directory
my $dir = shift // cwd; # cwd by default, or from input
my $re = qr/^\W[0-9]+\.[0-9]+/;
my @files_to_del = grep { /$re/ and not -d } glob "$dir/*";
say for @files_to_del; # please inspect first
#unlink or warn "Can't unlink $_: $!" for @files_to_del;
如果合適的話, glob
中的*
也可能有一些預選。 特別是,如果=
是文字字符(而不是 shell 打印的指示符,請參見腳注) ‡那么glob "=*"
將獲取以它開頭的文件,然后您可以通過grep
過濾器傳遞這些文件。
我排除了由-d
filetest標識的目錄,因為我們正在尋找文件(並且不要與unlink中關於目錄的一些可怕語言混合,感謝brian d foy
評論)。
如果您需要掃描子目錄並對它們執行相同的操作,也許是遞歸的——這里似乎不是這種情況? -- 然后我們可以在File::Find::find
(或File::Find::Rule
或其他)中使用此邏輯。
或者以任何其他方式讀取目錄( opendir
+ readdir
,像Path::Tiny
這樣的庫),然后過濾。
†或者,一個快速的單行...打印(檢查)即將被吹走的東西
perl -wE'say for grep { /^\W[0-9]+\.[0-9]+/ and not -d } glob "*"'
然后刪除它們
perl -wE'unlink or warn "$_: $!" for grep /^\W[0-9]+\.[0-9]+/ && !-d, glob "*"'
(我只是這樣切換到更緊湊的語法。沒有必要)
如果您希望能夠將目錄傳遞給它(可選,或在當前目錄中工作),那么請執行
perl -wE'$d = shift//q(.); ...' dirpath (relative path fine. optional)
然后在代碼中使用glob "$d/*"
。 這與上面腳本中的工作方式相同——shift從@ARGV
中提取第一個元素,如果在命令行上向腳本傳遞了任何內容,或者如果@ARGV
為空,則返回undef
然后//
(已定義-或) 運算符選取字符串q(.)
。
‡如果ls
已使用ls -F
別名,則前導=
可能是文件類型的“指示符”,可以通過運行帶有抑制別名的ls
來檢查什么,一種方法是\ls
(或檢查alias ls
)。
如果是這樣, =
代表它是一個套接字,可以通過-S
filetest 測試 Perl 中的內容。
那么建議的正則表達式中的\W
可能需要更改為\W?
允許在數字之前沒有非單詞字符,以及對套接字的測試。 喜歡
my $re = qr/^\W? [0-9]+ \. [0-9]+/x;
my @files_to_del = grep { /$re/ and -S } glob "$dir/*";
為什么不只是:
$ rm =*
有時,shell 命令是最佳選擇。
在這些情況下,我使用perl
來僅過濾文件列表:
ls | perl -ne 'print if /\A\W\d+\.\d+/a' | xargs rm
而且,當我這樣做時,我為沒有在grep
中使用擴展模式做一些更簡單的事情而感到內疚:
ls | grep -E '^\W\d+\.\d+' | xargs rm
最終我會遇到一個有目錄的問題,所以我需要更加小心文件列表:
find . -type f -maxdepth 1 | grep -E '^\./\W\d+\.\d+' | xargs rm
或者我也需要允許rm
刪除目錄:
ls | grep -E '^\W\d+\.\d+' | xargs rm -r
給你 go。
unlink( grep { /\W\d+\.\d+/ && !-d } glob( "*" ) );
這與文件名匹配,但不包括目錄。
要刪除與此匹配的文件名: /\W\d+\.\d+/
pcre ,請使用以下單行...
1> $fn
是一個文件名...我也刪除了my
關鍵字,因為單行代碼不必擔心perl 詞法范圍:
perl -e 'foreach $fn (grep { /\W\d+\.\d+/ } glob "*") {$cmd1="rm $fn";`$cmd1`;}'
2> 或者正如Andy Lester 所回答的那樣,也許他的回答是我們能做到的最有效的……
perl -e 'unlink(grep { /\W\d+\.\d+/ } glob "*");'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.