Назад | Перейти на главную страницу

найти команду с параметрами в переменной

> find /etc -name 'shells'
/etc/shells     # good !!

> SEARCH="-name 'shells'"; find /etc $SEARCH
# nothing found - bad !!

Почему команда "найти" не может принимать параметры в переменной?

Остальные команды в таком режиме работают нормально. Вероятно, это связано с пробелами и синтаксическим анализом. Как я могу сначала создать параметры в переменной, а затем выполнить «найти» с этими параметрами?

Чтобы было ясно, я хочу сделать цепочку -name xxxx -o -name yyyyy -o -name zzzzz, а затем найти все файлы одним запуском

ваша проблема в том, что простые кавычки интерпретируются не как таковые, а как входящие в ваши параметры.

Вы думаете, что выполнили это:

find /etc -name 'shells'

Когда на самом деле вы выполнили это:

find /etc -name \'shells\'

Имейте это в виду: В bash не игнорируются простые кавычки внутри двойных кавычек.

Итак, решение - не ставить простые кавычки:

SEARCH="-name shells"; find /etc $SEARCH

Лучшее решение - использовать кавычки, а затем использовать eval:

SEARCH="-name 'shells'"; eval " find /etc $SEARCH"

Проблема безопасности: Никогда, никогда не используйте предоставленную пользователем информацию в аргументе eval.

пытаться

eval find /etc $SEARCH
  • eval будет оценивать строку после расширения переменной

Попробуйте -name такой вариант:

SEARCH="shells"; find /etc -name $SEARCH

Взгляни на этот вопрос для некоторых вариантов.

Я настоятельно рекомендую избегать eval - он, как правило, отлично работает в простых тестах, но затем в производстве появляются неожиданные метасимволы оболочки и вызывают хаос. А если в строку входит ввод пользователя, то практически гарантировано, что у вас возникнут проблемы с безопасностью. Подумайте, что бы произошло, если бы кто-нибудь мог добавить x'$(rm /somethingimportant)'y в список шаблонов файлов.

Для подобных ситуаций, когда вы создаете команду динамически, гораздо лучше использовать массивы bash. Используйте что-то вроде:

namepatterns=(-name xxxx)
namepatterns+=(-o -name yyyyy -o -name "*.txt") # quotes prevent wildcard expansion
while read pattern; do
    namepatterns+=(-o -name "$pattern")
done <patternfile.txt

find /etc "${namepatterns[@]}"

В "${array[@]}" idiom обрабатывает каждый элемент массива как слово оболочки без какого-либо проблемного синтаксического анализа (разбиение слов, подстановочные знаки), от которого пострадает ссылка на переменную без кавычек.

Кстати, в приведенном выше примере я немного обманул, добавив первый -name xxxx первичный для массива без -o перед ним. Если бы вы строили массив полностью в цикле, это было бы сложнее:

namepatterns=()
while read pattern; do
    namepatterns+=(-o -name "$pattern")
done <patternfile.txt
# At this point the array starts with "-o" -- not what you want
# So use array slicing to remove the first element:
namepatterns=("${namepatterns[@]:1}")

find /etc "${namepatterns[@]}"

Видеть BashFAQ # 50: Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу! для более подробного обсуждения и вариантов построения и хранения команд.