Извлечение zip-файла, а затем переход в него с другим именем файла

Я создаю сценарий bash для извлечения tar-файла и перехода к нему, а затем запускает другой сценарий. До сих пор это работало довольно хорошо с моим кодом ниже, однако я столкнулся со случаем, когда, если извлеченная папка отличается от имени файла .tar, это может вызвать проблему. Итак, мой вопрос: как мне обрабатывать уникальные случаи, когда имя файла отличается от имени файла .tar.

например,) my_file.tar ---> после извлечения ----> my_ Different_file_name

#!/bin/bash

fname=$1

echo the file you are about to extract is $fname

if [ -f $fname ]; then         #if the file exists
    tar -xvzf $fname       #tar it
    cd ${fname%.*}         #the `%.*` will extract filename from     filename.tgz and cd into it
    echo ${fname%.*}
    echo $PWD
    loadIt                 #another script to load
fi

person tiger_groove    schedule 25.01.2016    source источник
comment
Будут ли ваши архивы создавать только один каталог верхнего уровня? Если это так, и ваш начальный каталог чист, то cd * будет работать (но это ненадежно, если это не так). Есть ли содержимое извлеченных архивов, которые вы можете использовать для поиска целевого каталога?   -  person Etan Reisner    schedule 25.01.2016
comment
@EtanReisner Нет, на этом же уровне могут быть другие каталоги, которые уже существуют, если бы я сделал cd *, я полагаю, что он будет перенесен в другой каталог, чем тот, который был только что извлечен.   -  person tiger_groove    schedule 26.01.2016


Ответы (3)


Вы можете сделать:

 topDir=$(tar -xvzf $fname | sed "s|/.*$||" | uniq)
 [ $(wc -w <<< $topDir) == 1 ] || exit 1
 echo topDir=$topDir

Объяснение: первая команда распаковывает vebosely (выводит все файлы, которые распаковывает), а затем получает все имена ведущих каталогов и передает их в uniq. (так что в основном он возвращает список всех каталогов верхнего уровня в файле tar). Следующая строка проверяет, что в topDir ровно одна запись, в противном случае происходит выход. В этот момент $topdir будет каталогом, в который вы хотите перейти.

person John    schedule 25.01.2016
comment
Когда я попробовал это, это дало мне [ 0 == 1 ] во второй строке. - person tiger_groove; 26.01.2016
comment
@kkmoslehour Вы использовали -v с tar? 0 для вывода wc означает отсутствие содержимого. - person Etan Reisner; 26.01.2016
comment
@John Да, я попробовал точный код, который у вас есть выше, но дал мне 0 для wc - person tiger_groove; 26.01.2016
comment
Это может быть несколько вещей: 1) tar-файл на самом деле пуст (попробуйте запустить tar -tf tarfile.tar.gz для подтверждения, 2) $fname не был правильно заполнен (либо он пуст, либо указывает на несуществующий tar-файл, либо указывает на tar, созданный не с помощью gzip). Это заставит tar выдать сообщение на stderr. 3) файл tar содержит только файлы (без подкаталогов). Вы можете попробовать вручную запустить tar -xvzf tarfile.tar.gz в командной строке, чтобы увидеть, что вы получите. - person John; 26.01.2016
comment
@John Это сработало, однако, не могли бы вы объяснить команду sed, которую вы там сделали, я не совсем понимаю, что она там делает. Также это будет работать только для файлов tgz, если бы файл был .zip, это не сработало бы, есть ли способ сделать то же самое для файлов zip? - person tiger_groove; 29.01.2016
comment
Команда sed использует команду s/regexp/replacement/. Обратите внимание, что я использовал | вместо / в качестве разделителя, так как лично мне это легче читать (вы можете использовать любой символ в качестве разделителя). Регулярное выражение /.*$. Это означает, что он ищет первую косую черту ( \\ ), затем сопоставляет любой символ (.), повторяющийся ноль или более раз (*), пока не достигнет конца ввода $. Затем он заменяет его заменой, которая в данном случае пуста. Другими словами, он находит первый \\ и стирает его и все, что следует за ним, оставляя вам только имя верхнего каталога. - person John; 29.01.2016

Может быть, вы могли бы сделать что-то вроде этого:

cd $(tar -tf $fname | head -1)
person Fredi    schedule 25.01.2016
comment
Нет никакой гарантии, что первая запись является каталогом верхнего уровня — некоторые tar-файлы вообще не хранят имена каталогов. - person John; 25.01.2016
comment
Подтвердить Я предположил, что каждый файл tar будет иметь одну и только одну папку верхнего уровня. Но если это не может быть гарантировано в этом конкретном случае, возможно, было бы лучше использовать find, чтобы убедиться, что loadIt существует, и найти его правильное местоположение. - person Fredi; 25.01.2016
comment
@Fredi Привет, это решение действительно может работать, однако, скажем, вместо tar это zip или любой другой сжатый файл, есть ли способ справиться с этим? - person tiger_groove; 26.01.2016
comment
Опять же, это не сработает, так как tar не гарантирует, что каталог верхнего уровня будет первой записью в файле tar. В зависимости от того, как был создан tar-файл (какая версия tar использовалась, сколько раз он запускался и т. д.), вы можете получить разные результаты. Предполагая, что это сделает ваш код подверженным ошибкам. Если вы хотите предположить, что все в папке находится в одном каталоге, вы можете использовать sed для удаления всего после первой / в первой записи файла tar. Это было бы безопаснее. - person John; 26.01.2016

Если вы не против переместить каталог после его извлечения, вы можете сделать что-то вроде этого

# Create a temporary directory
$ tmpd=$(mktemp -d)
# Change to the temporary directory
$ pushd "$tmpd"
# Extract the tarball
$ tar -xf "$fname"
# Glob the directory name
$ d=(*)
# Error if we have more (or less) than one directory
$ [ "${#d}" = 0 ] || exit 1
# Explicitly use just the first directory (optional since `$d` does the same thing)
$ d=${d[0]}
# Move the extracted directory to the previous directory
$ mv "$d" "$OLDPWD"
# Change back to the starting directory
$ popd
# Remove the (now empty) temporary directory
$ rmdir "$tmpd"
# Change into the extracted directory
$ cd "$d"
# Run 'loadIt'
$ loadIt
person Etan Reisner    schedule 25.01.2016