глобальная переменная обязательно в двойных кавычках

Эта ссылка: Подстановочные знаки внутри кавычек в моем случае не решить проблему.
Файл "a.sh" содержит:

file="path with wildcard*"

Файл "b.sh" содержит:

. a.sh
[ -f "$file" ] && echo ok

Поскольку

"$file"

не раскрывается подстановочный знак, вместо этого

$file

расширяется подстановочный знак, но с ошибкой: "ожидается двоичный оператор"

] Как мне решить эту загадку? Невозможно убрать подстановочный знак из двойных кавычек.

Редактировать:
Я хочу добиться одного совпадения с подстановочным знаком. Если совпадений больше, условие должно возвращать false, но ни в коем случае не должно возвращать ошибку.

0
17.06.2020, 19:49
3 ответа

Если вы хотите сохранить в массиве список файлов, полученный в результате расширения шаблона глобуса, хранящегося в переменной, в 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. Здесь выражение имеет вид $#,это специальный параметр, который расширяется до количества позиционных параметров, в данном случае количества аргументов этой анонимной функции, то есть количества файлов, полученных в результате этого расширения глобуса.
4
18.03.2021, 23:27

Я решил с помощью:
Файл "a.sh" содержит:

file=('path with wildcard'*)

Файл "b.sh" содержит:

. a.sh
[ -f "$file" ] && echo ok

Результат :Хорошо

-2
18.03.2021, 23:27
[ -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
2
18.03.2021, 23:27

Теги

Похожие вопросы