Setara dengan tar "--strip-components = 1" di unzip?

49

Saya memiliki skrip yang mengekstrak file tar.gz ke subdirektori mysubfolder yang ditentukan :

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

Apakah ada cara yang setara untuk melakukan ini dengan file zip?

sialan
sumber
2
Cukup gunakan bsdtar
drizzt

Jawaban:

26

Seperti kata Mathias, unziptidak memiliki opsi seperti itu, tetapi skrip bash satu-liner dapat melakukan pekerjaan itu.

Masalahnya adalah: pendekatan terbaik tergantung pada tata letak arsip Anda. Sebuah solusi yang mengasumsikan dir level atas tunggal akan gagal total jika konten langsung di root arsip (pikirkan /a/foo /b/foo /foodan kekacauan pengupasan /adan /b).

Dan kegagalan yang sama terjadi dengan tar --strip-component. Tidak ada solusi satu ukuran untuk semua.

Jadi, untuk mengupas akar dir, dengan asumsi ada adalah satu (dan hanya satu):

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

Pastikan saja file / dirs level kedua tidak memiliki nama yang sama dengan induk level atas (misalnya, /foo/foo). Tapi /foo/bar/foodan /foo/bar/barok. Jika ya, atau Anda hanya ingin aman, Anda bisa menggunakan dir temp untuk ekstraksi:

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

Jika Anda menggunakan Bash, Anda dapat menguji apakah tingkat atas adalah satu dir atau tidak menggunakan:

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

Berbicara tentang Bash, Anda harus menghidupkan dotglobuntuk memasukkan file tersembunyi, dan Anda dapat membungkus semuanya dalam satu fungsi yang berguna:

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"
)

Sekarang masukkan itu ke dalam ~/.bashrcatau ~/.profileAnda dan Anda tidak perlu khawatir lagi. Cukup gunakan sebagai:

unzip-strip sourcefile.zip mysubfolder

(pemberitahuan itu akan secara otomatis dibuat mysubfolderuntuk Anda jika tidak ada)

MestreLion
sumber
Ini tidak akan membuka ritsleting ke dalam struktur direktori yang ada seperti yang saya harapkan (saya mencoba untuk menggunakan. Di tempat mysubfolder). Saya akhirnya hanya membuka ritsleting (unzip zip-with-top-dir.zip) dan kemudian menyalin (cp -rv diekstraksi-top-zip-dir / *.).
catgofire
4

Saya tidak dapat menemukan opsi seperti itu di halaman manualunzip , jadi saya khawatir ini tidak mungkin. :(

Namun, (tergantung situasinya) Anda bisa mengatasinya. Misalnya, jika Anda yakin satu-satunya direktori tingkat atas dalam file zip dinamai foo-diikuti oleh nomor versi, Anda bisa melakukan sesuatu seperti ini:

cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder
Mathias Bynens
sumber
Pendekatan yang bagus, tetapi sedikit tidak lengkap: Anda masih akan memiliki foo * dir dengan konten yang diekstrak penuh.
MestreLion
Ya, saya tidak rm -rf foo-*sengaja menambahkan karena itu berpotensi berbahaya. Bagaimana jika sudah ada folder bernama foo-bar? Perhatikan bahwa ekstraksi sedang dilakukan di dalam /tmpfolder, yang akan dikosongkan secara otomatis setiap sekarang dan kemudian.
Mathias Bynens
Itu sebabnya saya merantai operasi menggunakan &&: langkah yang diberikan hanya terjadi jika langkah sebelumnya berhasil, sehingga yang terakhir (yang rm) hanya berjalan jika semua langkah selesai tanpa kesalahan.
MestreLion
2
Itu juga mengapa orang tidak boleh pengguna /tmp/some-hardcoded-folder-namesebagai folder temp, tetapi sebaliknya harus digunakan mktempuntuk itu: itu menjamin tidak akan ada folder yang ada. Periksa jawaban saya di bawah ini.
MestreLion
1

Anda dapat menggunakan -jjalur sampah (jangan membuat direktori). Ini hanya direkomendasikan untuk arsip tingkat tunggal yang agak umum. Arsip dengan struktur direktori multi level akan diratakan - ini bahkan dapat menyebabkan bentrokan nama untuk file untuk diekstraksi.

Dari halaman manual unzip:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
Pedro Rodrigues
sumber