解凍したtarの「--strip-components = 1」と同等ですか?


49

tar.gzファイルを指定されたサブディレクトリmysubfolderに抽出するスクリプトがあります。

mkdir mysubfolder; tar --extract --file=sourcefile.tar.gz --strip-components=1 --directory=mysubfolder;

これをzipファイルで行う同等の方法はありますか?


2
bsdtarを使用してください
drizzt

回答:


26

Mathiasが言ったように、そのunzipようなオプションはありませんが、1行のbashスクリプトで仕事をすることができます。

問題は、最適なアプローチがアーカイブレイアウトに依存することです。単一の最上位ディレクトリを想定するソリューション、コンテンツが直接アーカイブルートにある場合、惨めに失敗します(/a/foo /b/foo /fooストリッピング/aとの混乱を考えてください/b)。

そして、同じ失敗がで起こりtar --strip-componentます。万能のソリューションはありません。

そのため、ルートディレクトリを削除するには、 1つだけである仮定します。

unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"

第2レベルのファイル/ディレクトリが最上位の親と同じ名前(たとえば、)になっていないことを確認してください/foo/foo。しかし/foo/bar/foo/foo/bar/bar大丈夫です。そうした場合、または単に安全にしたい場合は、抽出に一時ディレクトリを使用できます。

temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
mv "$temp"/*/* "$dest" && rmdir "$temp"/* "$temp"

Bashを使用している場合、トップレベルが単一のディレクトリであるかどうかをテストできます:

f=("$temp"/*); (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] && echo "Single dir!"

Bashといえばdotglob、隠しファイルを含めるためにオンにする必要があり、すべてを単一の便利な関数でラップできます。

unzip-strip() (
    local zip=$1
    local dest=${2:-.}
    local temp=$(mktemp -d) && unzip -d "$temp" "$zip" && mkdir -p "$dest" &&
    shopt -s dotglob && local f=("$temp"/*) &&
    if (( ${#f[@]} == 1 )) && [[ -d "${f[0]}" ]] ; then
        mv "$temp"/*/* "$dest"
    else
        mv "$temp"/* "$dest"
    fi && rmdir "$temp"/* "$temp"
)

それをあなたの~/.bashrcorに入れれば、もう~/.profile心配する必要はありません。単に次のように使用します:

unzip-strip sourcefile.zip mysubfolder

mysubfolder存在しない場合は自動的に作成されます)


希望どおりに既存のディレクトリ構造に解凍されません(mysubfolderの代わりに。を使用しようとしました)。最終的に解凍(zip-with-top-dir.zipを解凍)してからコピー(cp -rv extract-top-zip-dir / *。)しました。
catgofire

4

のマニュアルページunzipそのようなオプションを見つけることができなかったので、これは不可能だと思います。:(

ただし、(状況に応じて)回避することができます。たとえば、zipファイル内の唯一の最上位ディレクトリの名前にfoo-バージョン番号が続いていることが確実な場合、次のようにすることができます。

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder

良いアプローチですが、少し不完全です:抽出されたコンテンツ全体を含むfoo * dirがまだあります。
メストレリオン

はい、それはrm -rf foo-*潜在的に危険なので、意図的に追加しませんでした。という名前のフォルダーが既にあった場合はどうなりますfoo-barか?抽出は/tmpフォルダ内で行われていることに注意してください。フォルダは時々自動的に空になります。
マティアスバイネンス

そのため&&、前のステップが成功した場合にのみ特定のステップが発生するため、すべてのステップがエラーなしで完了したrm場合にのみ、最後のステップ()が実行されます。
メストレリオン

2
また/tmp/some-hardcoded-folder-name、一時フォルダーとしてユーザーを使用mktempすることはできませんが、代わりにそのために使用する必要があります。それは、そのような既存のフォルダーがないことを保証します。以下の私の答えを確認してください。
メストレリオン

1

-jジャンクパスに使用できます(ディレクトリを作成しないでください)。これは、ある程度一般的な単一レベルのアーカイブにのみお勧めします。マルチレベルのディレクトリ構造を持つアーカイブは平坦化されます-これにより、抽出するファイルの名前の衝突が発生する可能性さえあります。

unzipのmanページから:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.