Unix: 각 폴더의 처음 N개 파일만 압축하는 방법은 무엇입니까?

Unix: 각 폴더의 처음 N개 파일만 압축하는 방법은 무엇입니까?

하위 폴더가 포함된 여러 수준의 2GB 이미지가 포함된 폴더가 있습니다.

Ntar 파일에 각 (하위) 폴더의 파일 만 보관하고 싶습니다 . find그때 사용해 보았지만 tail제대로 tar작동하지 못했습니다. 내가 시도한 것은 다음과 같습니다(가설 N = 10).

find . | tail -n 10 | tar -czvf backup.tar.gz

...이 오류를 출력합니다.

Cannot stat: File name too long

어떻게 되어가나요? 생각해 보세요. 작동하더라도 10개 파일이 아닌 모든 폴더의 처음 10개 파일만 압축할 것이라고 생각합니다.폴더.

N각 폴더의 파일을 얻는 방법은 무엇입니까 ? (서류주문 불필요)

답변1

pax-0옵션을 지원 하는 경우 다음을 사용하세요 zsh.

print -rN dir/**/*(D/e:'reply=($REPLY/*(ND^/[1,10]))':) |
  pax -w0 | xz > file.tar.xz

여기에는 목록의 각 디렉터리에 대한 처음 10개의 디렉터리가 아닌 파일이 파일 이름별로 정렬되어 포함됩니다. glob 한정자를 추가하여 다른 정렬 순서를 선택할 수 있습니다 om(수정 시간별 정렬, Om역순 정렬), oL(길이별 정렬), non(이름별 정렬, 번호별 정렬)...

표준 명령이 없거나 pax지원되지 않지만 -0GNU 명령이 있는 경우 tar다음을 수행할 수 있습니다.

print -rN -- dir/**/*(D/e:'reply=($REPLY/*(ND^/[1,10]))':) |
  tar --null -T - -cjf file.tar.xz

해당 권한이 없지만 zsh액세스 권한 bash(GNU 프로젝트의 셸)이 있는 경우 다음을 수행할 수 있습니다.

find dir -type d -exec bash -O nullglob -O dotglob -c '
  for dir do
    set -- "$dir/*"; n=0
    for file do
      if [ ! -d "$file" ] || [ -L "$file" ]; then
        printf "%s\0" "$file"
        (( n++ < 10 )) || break
      fi
    done
  done' bash {} + | pax -0w | xz > file.tar.xz

그러나 이렇게 하면 효율성이 크게 저하됩니다.

답변2

/tmp/dir각 (하위) 폴더의 N(예: N=10) 파일만 단일 파일에 보관하려는 홈 디렉토리가 있다고 가정합니다 backup.tar.gz.

tree:/tmp/dir

dir/                                                                                                                                                                                                           
├── one
│   ├── one10.txt
│   ├── one11.txt
│   ├── one1.txt
│   ├── one2.txt
│   ├── one3.txt
│   ├── one4.txt
│   ├── one5.txt
│   ├── one6.txt
│   ├── one7.txt
│   ├── one8.txt
│   ├── one9.txt
│   └── one_deep
│       ├── one_deep1
│       ├── one_deep10
│       ├── one_deep11
│       ├── one_deep2
│       ├── one_deep3
│       ├── one_deep4
│       ├── one_deep5
│       ├── one_deep6
│       ├── one_deep7
│       ├── one_deep8
│       └── one_deep9
├── three
│   ├── three10.txt
│   ├── three11.txt
│   ├── three1.txt
│   ├── three2.txt
│   ├── three3.txt
│   ├── three4.txt
│   ├── three5.txt
│   ├── three6.txt
│   ├── three7.txt
│   ├── three8.txt
│   ├── three9.txt
│   └── three_deep
│       ├── three_deep1
│       ├── three_deep10
│       ├── three_deep11
│       ├── three_deep2
│       ├── three_deep3
│       ├── three_deep4
│       ├── three_deep5
│       ├── three_deep6
│       ├── three_deep7
│       ├── three_deep8
│       └── three_deep9

암호:

cd /tmp; for i in `find dir/* -type d`; do find $i -maxdepth 1 -type f | tail -n 10 | xargs -I file tar -rf backup.tar file; done; gzip backup.tar

backup.tar.gz이렇게 하면 10개의 파일이 포함된 하위 폴더가 생성됩니다 /tmp/dir.

답변3

의 출력은 find단순하기 때문에 실제로 경로를 보지 않고는 어떤 파일이 동일한 디렉터리에 속하는지 알 수 없습니다. 또 다른 방법은 find경로를 확인하지 않고 여러 개의 s(각 폴더당 하나씩)를 사용하는 것입니다 . 이것이 제가하는 것입니다. 하위 폴더당 최대 10개의 파일을 압축하려면 다음과 같이 사용하세요.

for dir in $(find . -type d); do
  find "$dir" -maxdepth 1 -type f -printf "\"%p\"\n" | tail -10
done | xargs tar cvfz backup.tar.gz

현재 폴더의 모든 디렉터리를 재귀적으로 찾습니다. 각 디렉토리에 대해 최대 10개의 파일을 찾습니다.정확히폴더 ( -maxdepth 1). 전체 루프가 완료되면 tar루프에서 출력되는 모든 파일에 대해 명령이 실행됩니다. 또한 해당 옵션을 사용 $dir하여 find따옴표 안에 각 파일 이름을 인쇄함으로써 공백이 포함된 디렉터리 및 폴더 이름을 계산했습니다 -printf.

답변4

디렉터리 이름에 해시를 사용하고 해시 개수가 임계값 미만인 경우에만 파일 이름을 내보냅니다. 예를 들어

find . -depth -type f \
| perl -MFile::Spec -nle '(undef,$d,$f)=File::Spec->splitpath($_); print if $seen{$d}++ < 3' \
| tar ...

관련 정보