#bash #shell
#bash #оболочка
Вопрос:
В этой функции обрабатывается каталог файлов. Каталог должен содержать только то, что разрешено, как указано / настроено в массиве EXT. Цель функции — проверить, присутствует ли в каталоге расширение, которое не разрешено, т.Е. Если вы настроили только .mp3
и .png
в массиве EXT, при запуске функции, если она обнаруживает .gif
файл, она выдает ошибку. Технически мой код работает так, как есть сейчас, но проблема в том, что он всегда дает сбой при циклическом просмотре расширений.
# USER VARIABLES
INPUT=/home/administrator/music/v1.1/input
OUTPUT=/home/administrator/music/v1.1/output
declare -a EXT
EXT[0]=".png"
EXT[1]=".mp3"
function CHECK_EXT()
{
for FULLPATH in $INPUT/*; do
FULLNAME=$(basename -- "$FULLPATH")
i=0
for i in "${!EXT[@]}"; do
EXT="${EXT[$i]}"
if [[ $FULLNAME != *"$EXT" ]]; then
ERROR="Unsupported file type detected!"
return 0
fi
done
done
return 1
}
Комментарии:
1. Очевидно, что я опустил другой код, который вызывает функцию, и такой, поскольку он не нужен.
Ответ №1:
Вы можете переписать логику для проверки части расширения, как показано ниже. Идея заключается в том, чтобы сгенерировать строку для альтернативного сопоставления со всеми возможными поддерживаемыми расширениями, т. Е.
declare -A ext
ext[0]="png"
ext[1]="mp3"
теперь сгенерируйте строку, содержащую возможные совпадения расширений, и сохраните ее в переменной, используя printf -v
синтаксис, который сохраняет форматированную строку в переменной.
printf -v globStr '!(%s)' "$(IFS="|"; printf '%s' "${ext[*]}")"
Теперь с помощью !(opt1|opt2)
шаблона синтаксиса bash extglob
мы сопоставляем расширение имени файла, как показано ниже. Обратите внимание, что мы удалили .
символ из расширения массива. ${filename##*.}
Синтаксис удаляет части имени файла, оставляя только часть расширения.
if [[ ${filename##*.} == $globStr ]]; then
printf '%sn' "Only ${ext[*]} files are supported"
fi
Объединение всего вместе
#!/usr/bin/env bash
# ^^^^ needed for [[ operator to work, not POSIX compliant
input=/home/administrator/music/v1.1/input
output=/home/administrator/music/v1.1/output
declare -A ext
ext[0]="png"
ext[1]="mp3"
# The array expansion of type "${arr[*]}" generates a single string
# with the array contents based on the IFS value set. For alternate
# match we define a custom IFS value inside "$(..)" as the value
# defined inside it is not reflected outside.
printf -v globStr '!(%s)' "$(IFS="|"; printf '%s' "${ext[*]}")"
for file in "$input"/*; do
[ -f "$file" ] || continue
filename=$(basename -- "$file")
# The '==' inside the '[[..]]' enables the extglob option
# using which we match the set of not allowed filename extensions
if [[ ${filename##*.} == $globStr ]]; then
printf '%sn' "Only ${ext[*]} files are supported - got $filename"
fi
done
Обратите внимание на использование имен переменных в нижнем регистре для пользовательских переменных. Это всегда является хорошей практикой, поскольку имена в верхнем регистре зарезервированы для использования командной оболочкой.
Ответ №2:
Ваша проблема здесь:
EXT="${EXT[$i]}"
Вы перезаписываете EXT
содержимое массива при каждом запуске. Также вместо зацикливания индексов массива вы могли бы написать этот блок цикла следующим образом:
for FULLPATH in $INPUT/*; do
# check whether the file extension is NOT in the allowed EXT array
if [[ ! " ${EXT[@]} " =~ "$(basename -- "$FULLPATH")" ]]; then
ERROR="Unsupported file type detected!"
return 1
fi
done
Комментарии:
1. Ах, теперь это имеет смысл! Я уже переключился на решение выше, но также благодарю вас за вашу помощь.
Ответ №3:
ЭТО все, что вам нужно сделать, обращаясь только к тесту, о котором вы просили:
# USER VARIABLES
INPUT=/home/administrator/music/v1.1/input
OUTPUT=/home/administrator/music/v1.1/output
declare -A EXT
EXT[".png"]=1
EXT[".mp3"]=1
function CHECK_EXT()
{
for FULLPATH in $INPUT/*; do
if (( "${EXT[${FULLPATH##*.}]}" != 1 )); then
ERROR="Unsupported file type detected!"
return 0
fi
done
return 1
}
Существуют также другие способы улучшения скрипта, например, переменные в нижнем регистре, объявления локальных переменных, переменные в кавычках, стандартные возвращаемые значения success / fail и shebang. Это, непроверенное, ближе к тому, как вы действительно должны это написать:
#!/usr/bin/env bash
# USER VARIABLES
input_dir='/home/administrator/music/v1.1/input'
output_dir='/home/administrator/music/v1.1/output'
declare -A exts
exts[".png"]=1
exts[".mp3"]=1
function check_exts() {
local input_dir="$1" full_path ext
for full_path in "$input_dir"/*; do
ext="${full_path##*.}"
if (( "${exts[$ext]}" != 1 )); then
error='Unsupported file extension "'"$ext"'" detected!'
return 1
fi
done
return 0
}
check_exts "$input_dir" || { printf 'Failedn' >amp;2; exit 1; }
узнайте, как переменная error
действительно работает в вашем реальном коде.