find/exec 문의 결과 계산

find/exec 문의 결과 계산

간단한 호출로 sed수정 해야 하는 Perl 파일이 있습니다. 기본적으로 이 모든 항목의 첫 번째 줄을 삭제해야 합니다. 현재 나는 이것을 수행했습니다 :

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"

그리고 값은 자동으로 업데이트되어야 합니다. 하지만 countfind/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

이 솔루션은 이름에 이상한 문자가 포함된 파일에 작동하며 하위 쉘을 사용하지 않습니다.

그러나 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 ""}'

관련 정보