Відповіді:
Як сказав Матіас, 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
для вас, якщо його не існує)
Я не зміг знайти такий варіант на сторінках керівництваunzip
, тому боюся, що це неможливо. :(
Однак (залежно від ситуації) ви могли б обійти її. Наприклад, якщо ви впевнені, що єдиний каталог найвищого рівня у zip-файлі має ім'я foo-
та номер версії, ви можете зробити щось подібне:
cd /tmp
unzip /path/to/file.zip
cd foo-*
cp -r . /path/to/destination/folder
rm -rf foo-*
спеціально, оскільки це потенційно небезпечно. Що робити, якщо вже була папка з назвою foo-bar
? Зверніть увагу, що видобуток проводиться всередині /tmp
папки, яка щоразу автоматично видаляється автоматично.
&&
: даний крок відбувається лише в тому випадку, якщо попередній крок був успішним, тому останній (the rm
) виконується лише у тому випадку, якщо всі кроки виконані без помилок.
/tmp/some-hardcoded-folder-name
тимчасовою папкою, а замість цього використовувати mktemp
: це гарантує, що такої папки не буде. Перевірте мою відповідь нижче.
Ви можете використовувати -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).