Как отменить идентификацию каждого типа tar-файла в каталоге с помощью bash-скрипта?

#bash #if-statement #tar

#bash #if-statement #tar

Вопрос:

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

Это для установки Linux from 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:

Чтобы ваш скрипт работал с минимальными изменениями, используйте $afile всякий раз, когда вам нужно значение переменной. Знак доллара создает ссылку на переменную; в противном случае вы просто получаете литеральную строку 'afile' . Также избавьтесь от квадратных скобок и вместо echo переменной to 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 с помощью >amp;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" >amp;2
    esac
done
  

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

 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 {} ;
  

Комментарии:

1. for afile in *.tar.{gz,xz,bz2} Версия имеет потенциальную проблему: она будет запускать цикл с нерасширенным шаблоном для любых расширений, которые не соответствуют каким-либо файлам. Например, если нет файлов .tar.xz, он будет выполняться с afile="*.tar.xz" . Чтобы избежать этого, вы можете установить nullglob (с помощью shopt -s nullglob ) перед циклом (и отменить его с помощью shopt -u nullglob после, чтобы избежать неожиданных побочных эффектов).

2. * в пустом каталоге возникает та же проблема.