如果 sed 中包含正規表示式,如何跳過檔案?

如果 sed 中包含正規表示式,如何跳過檔案?

我目前使用以下簡化的命令刪除尾隨空格在文件末尾添加換行符在需要的地方:

find . -type f -exec sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' {} \+

正如您很快就會看到的,這有兩個問題:它會改變二進位檔案它會在文件末尾添加一個換行符␍␊ 行分隔符。在提交或類似操作時,這些修改很容易撤消或跳過git gui,但我想最大限度地減少*恢復量。為此:

有沒有辦法跳過所有的文件如果任何行匹配sed?中的正規表示式

* 我知道可能存在沒有 ␀ 字元的二進位文件,並且可能存在故意混合換行符或 ␀ 的文件。但我正在尋找需要最少人工幹預的解決方案。我可以可以想像列出我想要操作的所有檔案副檔名,但這將是一個非常長的列表,必須不斷檢查,並且由於名稱衝突,二進位檔案仍然有可能漏掉。

複雜的解決方法

while IFS= read -r -d '' -u 9
do
    if [[ "$(file -bs --mime-type -- "$REPLY")" = text/* ]]
    then
        sed -i -e 's/[ \t]\+\(\r\?\)$/\1/;$a\' -- "$REPLY"
    else
        echo "Skipping $REPLY" >&2
    fi
done 9< <(find . -type f -print0)

答案1

如果您相信 的git關於什麼是二進位檔案的觀點,您可以使用git grep來取得非二進位檔案的清單。假設t.cpp是一個文字文件,並且ls是一個二進位文件,兩者都已簽入:

$ ls
t.cpp ls
$ git grep -I --name-only -e ''
t.cpp

-I選項的含義是:

-I
不符合二進位檔案中的模式。

將其與您的sed表達式結合:

$ git grep -I --name-only -z -e '' | \
       xargs -0 sed -i.bk -e 's/[ \t]\+\(\r\?\)$/\1/;$a\'

-z/xargs -0幫助處理奇怪的檔案名稱。)

查看git grep手冊頁以獲取其他有用的選項 ---no-index或者--cached可能會有所幫助,具體取決於您想要操作的文件集。

答案2

如果任何行與 sed 中的正規表示式匹配,有沒有辦法跳過整個檔案?

就在這裡。

# test case for skipping file if a sed regex match succeeds

echo 'Hello, world!' > hello_world.txt
cat hello_world.txt
ls -li hello_world.txt

sed -i -e '/.*Hello.*/{q;}; s/world/WORLD/g' hello_world.txt # skips file
sed -i -e '/.*HeLLo.*/{q;}; s/world/WORLD/g' hello_world.txt

答案3

下面是一個 Perl 腳本,它迭代其參數(必須是檔案名稱)並向每個不以換行符號結尾的檔案附加換行符。包含空位元組的檔案將被跳過。已經以換行符號結尾的檔案不會被修改。包含 CR 的檔案會附加 CRLF,其他檔案則僅附加 LF。未經測試。

#!/usr/bin/env perl
foreach my $f (@ARGV) {
    open F, "<", $f or die;
    my $last = undef;
    my $cr = 0;
    while (<>) {if (/\0/) {undef $last; break} $last = $_; ++$cr if /\r$/}
    close F;
    if (defined $last && $last !~ /\n\Z/) {
        open F, ">>", $f or die;
        print($cr ? "\r\n" : "\n");
        close F or die;
    }
}

相關內容