ファイルを再帰的に抽出しますが、独自のフォルダに保存する方法は?

ファイルを再帰的に抽出しますが、独自のフォルダに保存する方法は?

以下は、フォルダ内のすべてのファイルを再帰的に抽出する方法です。

find -iname \*.epub -exec unzip -o {} \;

ただし、抽出されたファイルはすべて親フォルダに保存されます。

Parent (Extracted Epub files)
  Child (Epub files)
  Child (Epub files)

コマンドを独自のフォルダに抽出するようにコマンドを変更するにはどうすればよいですか?

Parent
  Child (Epub files and extracted Epub files)
  Child (Epub files and extracted Epub Files)

答え1

GNUを使用している場合は、そのfindタスクを使用してください-execdir

find -iname \*.epub -execdir unzip -o {} \;

これはファイルが見つかったすべてのディレクトリで実行され、ファイルがunzip適切なサブディレクトリに抽出されるようにします。

起動ディレクトリ(特にOpenBSD):

find /path/to/start -iname \*.epub -execdir unzip -o -- {} \;

答え2

Stephen Kittの-execdir答えは素晴らしいです。しかし、複数のファイルが.epub同じディレクトリにある可能性がある場合(-execdir役に立たない)、次のことを行う必要があります。

find ./ -iname '*.epub' -exec sh -c '
  for f; do
    rp="$(realpath -e "$f")"
    bn="$(basename "$f" .epub)"
    dn="$(dirname "$rp")/$bn"

    [ -e "$dn" ] && continue
    echo mkdir -p "$dn"
    echo unzip -d "$dn" -o "$rp"
  done' find-sh {} +

"$f"shスクリプトに渡された各パラメータ()の絶対realpathパス名全体を変数にインポートするために使用され、次に.epub拡張子を持たないデフォルトのrpファイルbasename名を変数にインポートするために使用されますbndirname絶対ディレクトリ名を取得して"/$bn"変数に追加するために使用されますdn。ところで、3つのプログラムはすべてGNUにありますコアツール

すでに存在する場合は、"$dn"ステートメントからそれをスキップします。continue必要に応じて、より多くのエラーチェックとエラー処理コードを追加することをお勧めします。それ以外の場合は、mkdir -punzipオプションで生成され、パラメータとして使用されます-d"$rp"使用するファイル名引数ですunzip

注:これはテスト実行で作成されたため、要求された内容のみを印刷します。会議していますが、実際にはしません。echo実際にディレクトリを作成し、ディレクトリに.epubファイルを抽出するようにコマンドからステートメントを削除します。

echo "$rp"または、ステートメントを追加しecho "$f"unzip's-qオプションを使用してファイル名を繰り返しながら、進行状況を表示し続けながら出力のノイズ量を減らすこともできます。

答え3

GNUを使用sedしてfind現在一般的な(標準ではありませんが)-iname/-print0述語実装をサポートしている場合は、次のことができます。

LC_ALL=C find . -iname '?*.epub' \
              ! -name '*[[*?]*' \
              ! -iname ..epub \
              ! -iname ...epub \
                -type f -print0 |
  LC_ALL=C sed -z 'h;s/\.epub$//;p;g' |
  xargs -r0n2 unzip -d

(一致するファイルを見つけるためにワイルドカードで処理されるバグを修正するには、または[文字を含むファイル名をスキップしてください。)*?unzip

どちらが実行されるのか

unzip -d ./path/to/file ./path/to/file.epub

epub拡張子なしでファイル名を付けたディレクトリにファイルの内容を抽出します。

また、そのディレクトリが問題になる可能性があるため、スキップし.epub?*前に少なくとも1バイトが必要です.)、..epubファイルをスキップします。...epub""...

またはzshを使用してください。

set -o extendedglob
for f (./**/(^*[[*?]*).(#i)epub(N.)) unzip -d $f:r $f

./**/(^(|.|..|*[[?*]*)).(#i)epub(ND.)ここでは隠し項目を省略し、必要に応じてglobをに変更します(再度.epub除く..epub...epub

zshを使用すると、次の文字を置き換えることで問題をよりよく解決できます。[?**[*]?[?]

set -o extendedglob
for f (./**/*.(#i)epub(N.)) unzip -d $f:r $f:h/${${f:t}//(#m)[[?*]/[$MATCH]}

あるいは、libarchiveなどのUnixyコマンドを使用してzipアーカイブを抽出することもできますbsdtar

set -o extendedglob
for f (**/*.(#i)epub(N.)) {
  mkdir -p -- $f:r && bsdtar -C $f:r -xf $f
}

または、find隠しアイテムを使用して含めます。

LC_ALL=C find . -iname '?*.epub' ! -iname ..epub ! -iname ...epub -exec sh -c '
  for file do
    dir=${file%.*}
    mkdir -p "$dir" &&
      bsdtar -C "$dir" -xf "$file"
  done' sh {} +

関連情報