Ответы:
Как сказал Матиас, unzip
такой опции нет, но однострочный скрипт bash может сделать эту работу.
Проблема в том, что наилучший подход зависит от формата вашего архива. Решение, которое предполагает один каталог верхнего уровня, с треском провалится, если контент находится непосредственно в корне архива (подумайте о /a/foo
/b/foo
/foo
хаосе удаления /a
и /b
).
И тот же сбой происходит с tar --strip-component
. Не существует единого решения для всех.
Итак, для удаления корневого каталога, предполагая, что есть один (и только один):
unzip -d "$dest" "$zip" && f=("$dest"/*) && mv "$dest"/*/* "$dest" && rmdir "${f[@]}"
Просто убедитесь, что файлы / каталоги второго уровня не имеют одинакового имени родителя верхнего уровня (например, /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"
)
Теперь вставьте это в свой ~/.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
папке, которая время от времени очищается автоматически.
&&
: данный шаг происходит только в том случае, если предыдущий шаг был успешным, поэтому последний ( 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).