4

Я написал скрипт, который конвертирует изображения в папку. Скрипт использует цикл for:

i="1"
for file in *.jpg; do
     outputFile=$(echo "image"$(echo $i))
     convert "$file" -resize 50x50 $outputFile
     i=$[i+1]
done

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

for file in *.jpg *.JPG *.jpeg; do
....
done

Проблема с этим заключается в том, что если вы находитесь в папке со всеми *.JPG и нет * .jpg, скрипт по-прежнему сталкивается с i+1, хотя изображений не было, потому что он все равно запускает цикл for, не найдя * .jpg, на который он идет *.JPG.

Как я могу настроить таргетинг на несколько расширений файлов, не запуская их для каждого типа? Пример, является ли их синтаксис примерно таким:

for file in [*.jpg | *.JPG]; do
...

?
Таким образом, моя выходная папка всегда содержит изображения, помеченные так:
image1.jpg
image2.jpg
image3.jpg
так далее..

Вместо того, чтобы в конечном итоге отсутствовала папка image1.jpg, потому что в ней не было * .jpg для запуска в первую очередь.

3 ответа3

6

Решение

Используйте нульглоб. Поместите следующую строку перед циклом for :

shopt -s nullglob

nullglob означает, что если такого файла нет, глобус удаляется из списка. Наблюдайте без nullglob:

$ echo  *.jpg *.JPG *.jpeg
test.jpg *.JPG *.jpeg

Теперь с помощью nullglob:

$ shopt -s nullglob
$ echo  *.jpg *.JPG *.jpeg
test.jpg

Пересмотренный скрипт

Полный сценарий может быть:

i=1
shopt -s nullglob
for file in *.jpg *.JPG *.jpeg; do
     convert "$file" -resize 50x50 "image$i.jpg"
     i=$((i+1))
done

Три ноты:

  1. В определении outputFile все эти операторы echo были ненужными.

  2. Следуя соглашению, я добавил расширение .jpg к имени вашего выходного файла. Если вы действительно не хотите расширение, просто удалите его.

  3. Я заменяю $[...] его более стандартной формой: $((...)) .

3
  1. Так как вы хотите искать несколько разных ( без учета регистра), ответ shopt -s nullglob очень полезен.
  2. Если вы просто искали *.jpg , *.JPG и другие шесть различных комбинаций верхнего и нижнего регистра, проще всего было бы

    for file in *.[Jj][Pp][Gg]
    

    который ищет файлы с именами

    • (что-то), а затем
    • . (точка), а затем
    • J или j , сопровождаемый
    • P или p , сопровождаемый
    • G или g

    другими словами,

    • (что-то), а затем
    • . (точка), а затем
    • "JPG", в некоторой комбинации верхнего и нижнего регистра
  3. Таким образом, один из способов решить вашу проблему

    shopt -s nullglob
    for file in *.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg]
    do …
    
  4. Трюк […] хорошо знать, но есть лучший способ.  Если бы я сказал вам, что есть опция оболочки под названием nocaseglob , вы могли бы догадаться, что она делает?

    shopt -s nullglob nocaseglob
    for file in *.jpg *.jpeg
    do …
    

    так что теперь *.jpg означает

    • (что-то), а затем
    • . (точка), а затем
    • "JPG", в некоторой комбинации верхнего и нижнего регистра

    и поэтому приведенная выше команда будет соответствовать *.jpg , *.JPG , *.Jpg , *.jpeg , *.jPeG и т.д.

  5. Другой способ - использовать опцию оболочки extglob для включения расширенных операторов сопоставления с образцом.  Вы все еще будете хотеть nullglob и nocaseglob .  Все расширенные операторы сопоставления с образцом выглядят как

    (some_special_character) ( шаблон списка )

    где пробелы добавлены для ясности, а pattern-list является списком pattern s, разделенных | персонажи).  Наиболее интересным для ваших целей является

    @ ( список шаблонов )

    что означает совпадение с одним из перечисленных шаблонов.  Так что теперь сценарий становится

    shopt -s nullglob nocaseglob extglob
    for file in *.@(jpg|jpeg)
    do …
    

    Это может показаться немного более типичным, но компромисс смещается с ростом числа расширений.  Рассматривать,

    for file in *.@(jpg|jpeg|jfif|exif|tif|tiff|gif|bmp|png|svg)
    

    немного короче

    for file in *.jpg *.jpeg *.jfif *.exif *.tif *.tiff *.gif *.bmp *.png *.svg
    
  6. Где ты научился делать $(echo …)?  Конечно, $(some_command(s) …) может быть полезен, а иногда даже $(echo …) , но вы злоупотребляете им.  Это совершенно приятно сказать

    outputFile="image$i"
    

    и вам, вероятно, даже не нужны кавычки ( в операторе присваивания).

  7. Хорошо, вы можете быть извинены только один раз , так как вы знаете, что значение outputFile является доброкачественным, поскольку вы устанавливаете его из константной строки непустых , не специальных символов ( image) плюс переменная, которую вы устанавливаете в константу строка непустых, не специальных символов ( 1) и выполняла только тривиальные арифметические операции над ней.  Но, как правило, вы всегда должны заключать в кавычки все ссылки на переменные оболочки, если только у вас нет веских причин не делать этого и вы уверены, что знаете, что делаете.  Так что ваша команда convert идеале должна быть

    convert "$file" -resize 50x50 "$outputFile"
    

    (с кавычками вокруг $outputFile .)

-1

Вы хотели бы заменить эту часть:

for file in *.jpg; do

Этим:

for file in $(ls *.jpg *.JPG); do

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