2

Я пытаюсь создать сценарий оболочки, который получает в качестве первого параметра путь к папке, и я хотел бы сжать все файлы с помощью gzip без перезаписи файлов .gz которые уже существуют в этой папке.

Я не знаю, по какой причине этот скрипт не работает должным образом:

#!/bin/bash
FOLDER=$1

cd $FOLDER
for f in *.*; do
  if [ ! -f "$f.gz" ]; then
    echo "Compressing $f file..";
    gzip $f
  else
    echo "Not overwriting $f.gz";
  fi
done

Иногда это путает, если файл является .gz файлом и не сжимает его.

1 ответ1

2

Ваши критерии неверны. *.* вернет все файлы с расширениями. Например, foo.gz Теперь вы проверяете следующее в псевдокоде:

if [ foo.gz.gz does not exist ]
    compress foo.gz to foo.gz.gz
else
    don't overwrite foo.gz.gz

Таким образом, ваша тестовая команда всегда будет сжиматься, потому что тест всегда будет иметь значение true. В конце вы всегда перезапишете свои файлы, потому что "$f.gz" расширится до foo.gz.gz


Если ваше реальное требование - сопоставить все, кроме файлов .gz в вашем текущем каталоге, Bash предлагает более простые способы сделать это, например, с помощью параметра extglob и отрицания.

#!/bin/bash
FOLDER=$1

shopt -s extglob

cd "$FOLDER"
for f in !(*.gz); do
  if [[ ! -d "$f" ]]; then
    gzip "$f"
  fi
done

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


Но на самом деле Linux предоставляет вам лучшие инструменты для поиска файлов, соответствующих определенным критериям. Чтобы (рекурсивно) найти все файлы, которые не заканчиваются на .gz и сжать их:

find /some/where -type f ! -iname '*.gz' -exec gzip '{}' \;

Если вы не хотите рекурсии:

find /some/where -type f -maxdepth 1 ! -iname '*.gz' -exec gzip '{}' \;

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .