find exec를 사용하여 하위 디렉터리에 중첩된 csv 파일의 행 수를 계산합니다.

find exec를 사용하여 하위 디렉터리에 중첩된 csv 파일의 행 수를 계산합니다.

find일부 중첩된 csv 파일의 결과에 대해 두 개의 파이프 명령을 실행하고 싶지만 비참하게 실패합니다.

아이디어는 다음과 같습니다.

$ find ./tmp/*/ -name '*.csv' -exec tail -n +2 {} | wc -l \;

~을 위한아니요각 CSV 파일의 헤더 행을 계산합니다.

명령 실패:

wc: ';': No such file or directory
find: missing argument to `-exec'

for이 경우 루프가 정말로 필요합니까?
예를 들어:

$ for f in ./tmp/*/*.csv; do tail -n +2 ${f} | wc -l; done

하지만 이렇게 하면 find파일 이름이 포함된 멋진 출력이 손실됩니다.

이 솔루션을 사용할 때 파일 이름도 손실되었습니다.find -exec의 파이프 명령?

$ find ./tmp/*/ -type f -name "*.csv" -print0 | while IFS= read -d '' f; do tail -n +2 "${f}" | wc -l; done

정확하게 말하자면, 인쇄된 파일 이름에 대해 이야기하는 것은 단일 파일에 대해 명령을 호출할 때 다음 결과에 익숙하기 때문입니다.

$ tail -n +2 | wc -l ./tmp/myfile.csv 
2434 ./tmp/myfile.csv

우분투 18.04를 사용합니다.

답변1

당신이 쓴다면

find ... -exec foo | bar \;

파이프는 호출 전에 쉘에 의해 해석됩니다 find. 결과적으로 파이프의 왼쪽은 이고 find ... -exec foo, 파이프의 오른쪽은 "'-exec'에 대한 인수 누락" 오류가 발생하는 것 같습니다 bar.

하우징 손상으로부터 수직 기둥을 보호합니다.

find ... -exec foo \| bar \;

첫 번째 다음 토큰은 명령 -exec으로 해석되고 종료자까지(포함하지 않음)까지의 모든 후속 토큰은 해당 명령에 대한 인수로 간주되기 때문에 도움이 되지 않습니다.find;+

바라보다"find"의 -exec 옵션 이해철저한 설명을 위해.

파이프를 사용하려면 -exec쉘을 호출해야 합니다. 예를 들어:

find ./tmp/*/ -name '*.csv' -exec sh -c '
  printf "%s %s\n" "$(tail -n +2 "$1" | wc -l)" "$1"' mysh {} \;

그런 다음 "매개변수 목록이 너무 깁니다" 오류가 발생하는 위험을 피하기 위해 ./tmp/*/다음과 같이 다시 작성할 수 있습니다.

find ./tmp -path './tmp/*/*' ...

또는 더 정확하게는 다음과 같이 tmp숨겨진 하위 디렉터리도 제외합니다( ./tmp/*/아마도 기본적으로 수행됨).

find ./tmp -path './tmp/.*' -prune -o -path './tmp/*/*' ...

-exec ... {} +마지막으로 발견된 단일 파일에 대해 셸을 호출하지 않는 더 빠른 변형을 사용할 수 있습니다 . 예를 들어 awk대신 다음을 사용합니다.tailwc

find ./tmp -path './tmp/.*' -prune -o -path './tmp/*/*' \
  -name '*.csv' -exec awk '
    BEGIN { skip = 1 }
    FNR > skip { lc[FILENAME] = (FNR - skip) }
    END { for (f in lc) print lc[f],f }' {} +

( awk개행 문자로 끝나지 않는 잘못된 행도 계산됩니다 wc.)

답변2

원하는 것이 각각에서 1을 빼는 것이라면 wc -l이는 매우 간단합니다.

find [whatever you want] -exec wc -l {} + | perl -pe 's/(\d+)/$1-1/e'

관련 정보