Как распаковать все типы tar-файлов в каталоге с помощью bash-скрипта? - PullRequest
2 голосов
/ 09 апреля 2019

Я новичок в написании сценариев bash для автоматизации задач, и я пытаюсь распаковать все файлы tar в одном каталоге (их слишком много, чтобы сделать это вручную) для набора файлов исходного кода.Все они типа * .tar.gz, * .tar.xz или * .tar.bz2.

Это для установки Linux из Scratch LFS, которую я делаю (япервый таймер), и я не уверен, как еще автоматизировать эту задачу, кроме использования скрипта bash.Код моего маленького скрипта для этого приведен ниже.

#!/bin/bash
for afile in 'ls -1'; do
    if [ 'afile | grep \"\.tar\.gz\"' ];
    then
        tar -xzf afile
    elif [ 'afile | grep \"\.tar\.xz\"' ]
    then
        tar -xJf afile
    elif [ 'afile | grep \"\.tar\.xz\"' ]
    then
        tar -xjf afile
    else
        echo "Something is wrong with the program"
    fi
done;

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

tar (child): afile: Cannot open: No such file or directory
tar (child): Error is not recoverable: exiting now
tar: Child returned status 2
tar: Error is not recoverable: exiting now

Очевидно, он думает, что файл - это файл, но я не знаю, как изменить файл на файл, который проходит через мою конструкцию for.Как бы я написал сценарий для этого, тем более что существуют разные типы файлов?

1 Ответ

2 голосов
/ 09 апреля 2019

Чтобы ваш скрипт работал с минимальными изменениями, используйте $afile всякий раз, когда вам нужно значение переменной.Знак доллара делает переменную ссылку;в противном случае вы просто получите буквальную строку 'afile'.Также избавьтесь от квадратных скобок и вместо echo переменной grep.

for afile in `ls -1`; do
    if echo "$afile" | grep '\.tar\.gz'
    then
        tar -xzf "$afile"
    elif echo $afile | grep '\.tar\.xz'
    then
        tar -xJf "$afile"
    elif echo "$afile" | grep '\.tar\.bz2'
    then
        tar -xjf "$afile"
    else
        echo "Something is wrong with the program"
    fi
done

Поскольку вы новичок в bash, давайте рассмотрим различные другие способы написания сценария.Я бы сделал пару улучшений.Например, вы не должны зацикливаться на ls.Вы можете получить то же самое, зациклившись на *.Во-вторых, grep - тяжелый инструмент.Вы можете сделать несколько простых сравнений строк со встроенными конструкциями оболочки, такими как [[ и ==.

for afile in *; do
    if [[ "$afile" == *.tar.gz ]]; then
        tar -xzf "$afile"
    elif [[ "$afile" == *.tar.xz ]]; then
        tar -xJf "$afile"
    elif [[ "$afile" == *.tar.bz2 ]]; then
        tar -xjf "$afile"
    else
        echo "Something is wrong with the program"
    fi
done

На самом деле, это было бы еще лучше с оператором case.Давайте попробуем это.Также давайте повторим сообщение об ошибке в stderr с >&2.Это всегда хорошая идея.

for afile in *; do
    case "$afile" in
        *.tar.gz)  tar -xzf "$afile";;
        *.tar.xz)  tar -xJf "$afile";;
        *.tar.bz2) tar -xjf "$afile";;
        *) echo "Something is wrong with the program" >&2
    esac
done

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

for afile in *.tar.{gz,xz,bz2}; do
    case "$afile" in
        *.tar.gz)  tar -xzf "$afile";;
        *.tar.xz)  tar -xJf "$afile";;
        *.tar.bz2) tar -xjf "$afile";;
    esac
done

Или совершенно другой способ сделать это: используйте find, чтобы найти все файлы, и его действие -exec, чтобы вызвать команду для каждого файла.это находит.Здесь {} является заполнителем для файлов, которые он находит.

find . -name '*.tar.gz'  -exec tar -xzf {} \;
find . -name '*.tar.xz'  -exec tar -xJf {} \;
find . -name '*.tar.bz2' -exec tar -xjf {} \;
...