Эта ссылка: Подстановочные знаки внутри кавычек
в моем случае не решить проблему.
Файл "a.sh" содержит:
file="path with wildcard*"
Файл "b.sh" содержит:
. a.sh
[ -f "$file" ] && echo ok
Поскольку
"$file"
не раскрывается подстановочный знак, вместо этого
$file
расширяется подстановочный знак, но с ошибкой: "ожидается двоичный оператор"
] Как мне решить эту загадку? Невозможно убрать подстановочный знак из двойных кавычек.
Редактировать:
Я хочу добиться одного совпадения с подстановочным знаком. Если совпадений больше, условие должно возвращать false, но ни в коем случае не должно возвращать ошибку.
Если вы хотите сохранить в массиве список файлов, полученный в результате расширения шаблона глобуса, хранящегося в переменной, в bash
, это будет:
pattern='path with wildcard*'
IFS= # disable splitting
shopt -s nullglob # make globs that don't match any file expand to nothing
# instead of the unexpanded pattern.
files=($pattern) # here using split+glob (unquoted expansion in list context)
# with the splitting disabled above.
Или назначить массив $files
напрямую без использования скалярной переменной $pattern
:
shopt -s nullglob # make globs that don't match any file expand to nothing
# instead of the unexpanded pattern.
files=('path with wildcard'*)
Затем вы можете проверить, пуст ли этот список, с помощью:
if [ "${#files[@]}" -gt 0 ]; then
echo it did find some files
fi
Если вы хотите проверить, что среди этих файлов хотя бы один является обычным файлом (после разрешения символической ссылки ), вы можете сделать:
has_regular_files() {
local file
for file do
[ -f "$file" ] && return
done
false
}
if has_regular_files "${files[@]}"; then
echo there was at least one regular file in the list
fi
Чтобы убедиться, что он соответствует только одному файлу и что этот файл является обычным файлом:
if [ "${#files[@]}" -eq 1 ] && [ -f "${files[0]}" ]; then
echo one and only one file matches and it is regular.
fi
Чтобы проверить, соответствует ли он хотя бы одному обычному файлу и что все совпавшие файлы являются обычными:
only_regular_files() {
[ "$#" -gt 0 ] || return
local file
for file do
[ -f "$file" ] || return
done
}
if only_regular_files "${files[@]}"; then
echo at least one regular file and all are regular.
fi
В оболочке zsh
вы можете использовать квалификаторы glob для сопоставления по типу файла:
if ()(($#)) $~pattern(N-.); then
print at least one regular file in the expansion of the pattern.
fi
bash
, zsh
не выполняет неявное разбиение + подстановку при расширении параметра без кавычек. Здесь мы просим подстановку (, но не разбиение )на $~pattern
. (N-.)
glob, N
для nullglob
, чтобы, если glob не соответствует ни одному файлу, он расширялся до нуля .
для проверки только обычных файлов (за исключением файлов любого другого типа ), -
, чтобы этот тест был выполнен после разрешения символической ссылки, чтобы он также соответствовал файлам, которые являются символическими ссылками на обычные файлы (, такие как ваш [ -f "$file" ]
будет ). () {body} args
где {body}
равно (($#))
. ((expr))
— это оператор оценки арифметического выражения в стиле ksh -, который возвращает true, если выражение оценивается как число, отличное от 0. Здесь выражение имеет вид $#
,это специальный параметр, который расширяется до количества позиционных параметров, в данном случае количества аргументов этой анонимной функции, то есть количества файлов, полученных в результате этого расширения глобуса. Я решил с помощью:
Файл "a.sh" содержит:
file=('path with wildcard'*)
Файл "b.sh" содержит:
. a.sh
[ -f "$file" ] && echo ok
Результат :Хорошо
[ -f $file ] && echo ok
Это расширит переменную, wordsplit и расширит все соответствующие файлы. Вы можете получить [ -f filethis filethat ]
, а filethis
не является бинарным оператором, поэтому вы получите ошибку.
Даже если совпадений нет и $file
заменяется ничем, вы получаете [ -f ]
, который является проверкой того, является ли -f
не пустой -строкой. Так и есть, результат верный.
Разверните имена файлов в массив или в позиционные параметры и подсчитайте совпадения:
file="path with wildcard*"
IFS=
set -- $file
echo "matched $# files"
Вы должны изменить здесь IFS
, если у вас есть пробелы в шаблоне, потому что разделение происходит до расширения имени файла, поэтому вышеприведенное будет иметь два постоянных слова и один шаблон глобуса. Также непревзойденный шаблон останется, как -, поэтому нам нужно проверить это.
Вы можете скрыть это в функции:
only_one() {
local IFS=
set -- $1
if [ $# = 1 ] && [ -f "$1" ]; then return 0; fi
return 1
}
, а затем запустите
if only_one "$file"; then
...
fi