Еквівалентний tar - "- strip-компоненти = 1" в розпакуванні?


49

У мене є сценарій, який витягує файл tar.gz у вказаний підкаталог mysubfolder :

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

Чи є еквівалентний спосіб зробити це за допомогою zip-файлу?


2
Просто використовуйте bsdtar
drizzt

Відповіді:


26

Як сказав Матіас, unzipнемає такої можливості, але однолінійний сценарій баш може зробити цю роботу.

Проблема полягає в тому, що найкращий підхід залежить від макета вашого архіву. Розв’язання, яке передбачає єдиний dir верхнього рівня, вийде з ладу, якщо вміст знаходиться безпосередньо в корені архіву (подумайте /a/foo /b/foo /fooі про хаос зняття /aта /b).

І те саме відбувається і з tar --strip-component. Не існує рішення одного розміру.

Таким чином, щоб позбавити кореневої каталог, припускаючи , що це один (і тільки один):

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

Просто переконайтесь, що файли / dirs другого рівня не мають того самого імені батьківського верхнього рівня (наприклад, /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, ви можете перевірити, чи верхній рівень є одним dir чи не використовується:

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

Тепер покладіть це у свій ~/.bashrcабо ~/.profileі вам більше ніколи не доведеться турбуватися про це. Просто використовуйте як:

unzip-strip sourcefile.zip mysubfolder

(зауважте, він автоматично створиться mysubfolderдля вас, якщо його не існує)


Це не розпакує існуючу структуру каталогу, як я сподівався (я намагався використовувати. Замість mysubfolder). У кінцевому підсумку я просто розпакував (unzip zip-with-top-dir.zip) і потім скопіював (cp -rv extracted-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 з повним вилученим вмістом.
MestreLion

Так, я не додав rm -rf foo-*спеціально, оскільки це потенційно небезпечно. Що робити, якщо вже була папка з назвою foo-bar? Зверніть увагу, що видобуток проводиться всередині /tmpпапки, яка щоразу автоматично видаляється автоматично.
Mathias Bynens

Ось чому я ланцюг операцій, використовуючи &&: даний крок відбувається лише в тому випадку, якщо попередній крок був успішним, тому останній (the rm) виконується лише у тому випадку, якщо всі кроки виконані без помилок.
MestreLion

2
Ось чому ніколи не слід користуватися /tmp/some-hardcoded-folder-nameтимчасовою папкою, а замість цього використовувати mktemp: це гарантує, що такої папки не буде. Перевірте мою відповідь нижче.
MestreLion

1

Ви можете використовувати -jдля небажаних шляхів (не робіть каталогів). Це рекомендується лише для дещо поширених однорівневих архівів. Архів із багаторівневою структурою каталогів буде вирівняний - це може призвести навіть до зіткнення назв для файлів, які потрібно витягнути.

Зі сторінки розпакування:

   -j     junk  paths.   The  archive's directory structure is not recreated; all files are deposited in the
          extraction directory (by default, the current one).
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.