Как я могу заставить unzip / zip не создавать подкаталог при его распаковывании?


19

В зависимости от того, как создается zip-файл, иногда он извлекает все файлы напрямую, а иногда он извлекает файлы в подкаталог.

Если последнее верно, как я могу заставить unzipкоманду «игнорировать» этот каталог первого уровня?

Пример:

cd /tmp
wget http://omeka.org/files/omeka-1.5.1.zip
mkdir omeka
unzip omeka-1.5.1.zip -d omeka/
cd omeka/
ll

Что я получаю это /tmp/omeka/omeka-1.5.1/:

total 12
drwxr-xr-x 3 root root 4096 2012-05-08 18:44 ./
drwxrwxrwt 6 root root 4096 2012-05-08 18:44 ../
drwxr-xr-x 5 root root 4096 2012-04-20 14:54 omeka-1.5.1/

Мне нужны файлы, извлеченные /tmp/omeka/(на один уровень выше, и номер версии не включен в структуру каталогов)

/tmp/omeka/(files)

Я знаю, что могу использовать эту -jопцию для «ненужных путей», но я хочу сохранить структуру подкаталогов, но не структуру каталогов верхнего уровня. Как я могу это сделать?


PS: я знаю, что я могу извлечь и затем mvфайлы, но я хотел посмотреть, есть ли способ сделать это прямо из команды unzip
cwd

Я не знаю ни одного. Но если имя файла всегда соответствует (кроме расширения) имени каталога, довольно просто написать сценарий переименования извлеченного dir.
Мат

3
Я вижу, что вы пытаетесь сделать, но я бы не рекомендовал это. Удаление номера версии из источников вашего проекта - плохая идея; Вы должны просто извлечь и использовать ln -s, если вы хотите более короткое имя без информации о версии. Таким образом, вы всегда будете знать, какую версию вы используете, и можете легко обновить ее до новой, переключив ссылку.
Бертон Самоград

@BurtonSamograd - это было бы идеально, но мне все еще интересно, есть ли эффективный способ сделать это, потому что какое-то программное обеспечение, например, Wordpress, помещает каждую версию в /wordpress/каталог (без номера версии) внутри zip-файла. Это действительно хорошо unzipи тогда, mvно отсутствие контроля над этим и необходимость сделать это в два шага всегда немного раздражали меня. К счастью, Wordpress также имеет .tar.gzвкус :)
cwd

Попробуйтеcd /tmp/omeka && ln -s -T . omeka-1.5.1
Джеймс Янгман

Ответы:


4

Используйте файловую систему FUSE, которая позволяет просматривать архивы, такие как каталоги, такие как AVFS . Используйте cpдля извлечения файлов в каталог по вашему выбору.

mountavfs
cp -Rp ~/.avfs/tmp/omeka-1.5.1.zip\#/omeka-1.5.1 omeka

Поскольку мы предполагаем, что в архиве имеется один каталог верхнего уровня, вы можете сократить его до

cp -Rp ~/.avfs/tmp/omeka-1.5.1.zip\#/* omeka

@ Джайлс, вы - эксперт, который приходит и отвечает на все вопросы, на которые никто не может ответить, поэтому я думаю, что это действительно единственный способ сделать это. Я надеялся, что unzipу меня будет какое-то волшебство, например, указание файлов, которые нужно извлечь */*, которые я мог бы использовать, не устанавливая другую утилиту, но, думаю, нет. Благодарю. +1
cwd

6

Если ваш zip-файл не содержит структуру каталогов или вам не нужно его сохранять, вы можете использовать это:

cd /tmp
wget http://omeka.org/files/omeka-1.5.1.zip
unzip -j omeka-1.5.1.zip -d omeka
cd omeka
ll

3

Этот скрипт не является надежным, но работает в простых случаях:

...
dest=omeka
unzip omeka-1.5.1.zip -d $dest/

if [ `ls $dest | wc -l` == 1 ]; then
  subdir=`ls $dest`
  mv $dest/$subdir/* $dest/
  rmdir $dest/$subdir
fi

Он просто проверяет, существует ли ровно один подкаталог, и если да, удаляет из него все, а затем удаляет его.


2

Я только что зарегистрировался сегодня, поэтому я не могу поднять ответ @SteveBennet и не могу добавить комментарий там.

Основываясь на его ответе, я создал рекурсивную функцию, подобную этой:

...

shopt -s dotglob # To include hidden files in the move command

function moveSub {
  local dest=$1
  if [ `ls $dest | wc -l` == 1 ]; then
    local subdir=`ls $dest`
    moveSub "$dest/$subdir"
    mv $dest/$subdir/* $dest/
    rmdir $dest/$subdir
  fi
}

moveSub "$dest"

Как сказал @SteveBennet: этот скрипт не является надежным, но работает в простых случаях.

Надеюсь, это полезно.


1

Нужно выглядит как patch --strip=nвариант

Было бы желательно иметь параметр, подобный patch --strip=number(или -pnumber), который numberвначале прерывает компоненты пути (см. Сравнение и объединение файлов: каталоги исправлений ).

Другое решение, применимость

В противном случае, есть другое решение, вроде хакерское, но работает. В моем случае я хотел перезаписать каталог, заполненный существующими файлами, содержимым zip, без предварительного извлечения полного zip.

Когда это решение сработает и будет доступно решение @ Gilles, последнее также сработает. Однако это решение не требует наличия файловой системы FUSE.

Как это сделать

Предполагая, что вы знаете дополнительный каталог, в вашем случае omeka-1.5.1вы можете сделать это:

mkdir omeka
ln -s . omeka/omeka-1.5.1 # create a symlink that redirects output
unzip omeka-1.5.1.zip -d omeka/
rm omeka/omeka-1.5.1 # remote symlink

unzipпопытается распаковать архив, omeka-1.5.1который на самом деле является символической ссылкой на содержащий каталог. В результате файлы попадут omekaнапрямую.

Возможные варианты

Можно представить варианты перенаправления одной или нескольких частей иерархии зависимостей.

ln -s ../myfoo omeka/omeka-1.5.1/foo
ln -s ../../mybarxyzzy omeka/omeka-1.5.1/subdir/bar

Вывод

Это решение несколько специфично, но у него есть свои варианты использования, и я просто случайно использовал его.


Отличное решение, если вы знаете путь!
grepsedawk

Путь можно проверить, перечислив сначала содержимое zip-файла, например, с помощью unzip -l. Это может даже быть автоматизировано с помощью сценария, который вычисляет часть пути, который является общим.
Стефан Гуричон

О, это намного проще, если вы знаете путь. Я немного поиграл с unzip -l, но это было немного больше grep / sed / awk, чем я хотел, поэтому я отступил.
grepsedawk

zipinfo -1может быть хорошим началом Какой у вас вариант использования?
Стефан Гурихон

github.com/grepsedawk/wow-config/blob/… в этом случае я знаю каталог :)
grepsedawk

1

Скорее всего, вы хотите запустить unzipс -jопцией, как в:

unzip -j files.zip -d ./output/

Но вы можете быть удивлены его поведением:

-j мусорные пути. Структура каталогов архива не воссоздается; все файлы хранятся в каталоге извлечения (по умолчанию текущий).

Если вы извлечете files.zipв выходной каталог, ./outputи вы получите это в результате:

./output/files/subfolder1/f1
./output/files/subfolder1/f2

тогда -jопция даст вам это (все пути чередуются):

./output/f1
./output/f2
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.