計算 find/exec 語句中的結果

計算 find/exec 語句中的結果

我有一些 Perl 文件,我必須透過一個簡單的sed呼叫來修改它們。基本上,我必須刪除所有這些的第一行。目前,我設法做到了這一點:

find <PATH> -type f -name "*.pl" -exec sed -i '1d' {} \;

然而,我在腳本中使用了這一行,我希望它更......健談。因此,我決定回顯一個計數器(即時),這將顯示到目前為止已處理的檔案數量。

我知道 Perl 文件的數量可以透過以下方式檢索

PERL_FILE_COUNT=$(find <PATH> -name "*.pl" | wc -l)

目前,我有這個

remove_first_line()
{
    count=0
    echo -ne "Removing first line of Perl files ..."
    find <PATH> -type f -name "*.pl" -exec sed -i '1d' {} \; >/dev/null 2>&1

    if [ $? -eq 0 ]
        then echo "OK"
        then echo "FAILED"
    fi
}

現在,我想要的輸出是這樣的:

"Removing first line of Perl files ... 1/209209"

並且該值應該會自動更新。但我不知道如何count使用 find/exec 語句來增加變數。基本上,每次sed完成文件的工作時,都應該增加count變數。

答案1

如果您有 bash 4,請考慮使用 globstar。它為您提供遞歸通配符。

shopt -s globstar
perlz=( **/*.pl ) # */ Hack to fix syntax highlighting
totes="${#perlz[@]}"
i=0
for file in "${perlz[@]}"; do
    printf 'Removing first line of Perl files … %d/%d\r' $((++i)) $totes
    ed -s "$file" <<< $'1d\nw' # You can use `sed` if you want to, but ed is an actual file editor
done
echo # print a final newline

此解決方案將適用於名稱中包含瘋狂字元的文件,並避免使用子 shell。

但如果 bash 4 不是一個選項,您可以使用以下命令重新建立此解決方案find -exec +

find . -name '*.pl' -exec bash -c 'totes=$#
  i=0
  for file; do
    printf "Removing first line of Perl files … %d/%d\r" $((++i)) $totes
    ed -s "$file" <<< $'\''1d\nw'\'' # Avoid these leaning toothpicks by putting this
                                     # script in a file.
  done
  echo # print a final newline
' bash {} +

但是,這取決於系統的 ARG_MAX(與上面不同),因此如果檔案數量非常大,您仍然可能最終會對檔案的子集進行多次執行。

答案2

這個怎麼樣?

#!/bin/bash

failed=0

find . -type f -name "*.pl" | while read file; do
   if [ -e "$file" ] && [ -r "$file" ]; then
     sed -i~ "1d" "$file"
     if [ $? != 0 ]; then
        echo "sed returns $? on ($file)"
        (( failed++  ))
     fi
   else
      echo "warning ($file) not exists, or not readable"
      (( failed++ ))
   fi
done

echo "failed execution: $failed"

在這裡使用比較安全sed -i~。 Sed 將舊文件另存為file~.

答案3

GNUly:

find . -type f -name '*.pl' -size +0c -print0 > list &&
  count=$(grep -cz . < list) &&
  stdbuf -oL xargs < list -r0 sed -i -e '1{w /dev/stdout' -e 'd;}' |
    awk -v c="$count" '{printf "processed file %d/%d\r", NR, c}
                       END{print ""}'

相關內容