> 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
Попробуйте -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: Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу! для более подробного обсуждения и вариантов построения и хранения команд.