Unix:各フォルダの最初のN個のファイルのみを圧縮する方法は?

Unix:各フォルダの最初のN個のファイルのみを圧縮する方法は?

サブフォルダーを含む複数レベルの2 GBイメージを含むフォルダーがあります。

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修飾子を追加することで、別のソート順を選択できますomOmoLnon

標準コマンドがないか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(各フォルダごとに1つ)を使用することです。これが私がすることです。サブフォルダごとに最大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 ...

関連情報