Функция BASH не экранирует управляющие символы
Эй, ребята, у меня есть функция, которую я использую, чтобы найти вещи, но, к сожалению, каждый раз, когда я передаю ей управляющий символ ($intVal или же testing : и т.д.) это душит. Мне было интересно, что это было за исправление?
Я могу понять, что с помощью $ или же % или же : и т.д. в grep без экранирования вызывает эту проблему, но так как я передаю его по ссылке, я не уверен, как избежать этого...
Во всяком случае, вот код.
function ffind()
{
if [ $1 ] ; then
find -type f | grep -ir '$1' * | grep -v '.svn'
else
echo "'$1' is not a valid resource"
fi
}
Примеры):
$ ffind $intVal
'' is not a valid resource
$ ffind "testing :"
bash: [: testing: unary operator expected
'testing :' is not a valid resource
1 ответ
Первый пример
$ ffind $intVal
'' is not a valid resource
Это не работает, потому что $foo это синтаксис для переменных, и у вас нет переменной с именем intVal установить, так $intVal переводится в пустую строку. Поскольку переменная также не заключена в кавычки, аргументы вообще не передаются ffind,
Чтобы это исправить, избегайте $ - или \$intVal (обратная косая черта) или '$intVal' (В одинарных кавычках).
Если у вас на самом деле есть переменная с именем intVal впрочем, вместо этого заключите в двойные кавычки - "$intVal" - это расширит значение переменной, но не разделит ее.
Обратите внимание, что в bash нет такой вещи, как "передача по ссылке". Существует только передача по значению и (хитрая) передача по имени.
Второй пример
$ ffind "testing :"
bash: [: testing: unary operator expected
'testing :' is not a valid resource
Это не работает, потому что вы забыли поставить кавычки $1 в if [ $1 ] поэтому он может быть разделен по словам, и три аргумента передаются [ встроенная:
- "
[" - "
testing" - "
:" - "
]"
вместо ожидаемых двух:
- "
[" - "
testing :" - "
]"
Пример № 1 также зависит от этого, так как [ $1 ] распадается на (" [ "," ] ") и не (" [ "," "," ] "). Пример № 1 работает случайно, так как, по-видимому, [ ] является действительным. (Я этого не знал...)
Чтобы решить эту проблему, поместите двойные кавычки $1 - [ "$1" ],
Примечание: пока [ стандартно, есть также специфичный для bash [[ оператор, который на самом деле имеет правила синтаксического анализа, отличные от остальной части кода - в частности, он не разделяет расширенные переменные. В Баш, [[ $1 ]] а также [[ "$1" ]] оба эквивалентны, в отличие от их [ альтернативы.
Больше ошибок
У вашей функции также есть несколько других проблем, которые не показаны в примерах.
find -type f | grep -ir '$1' * | grep -v '.svn'
В этой строке:
Слово
'$1'вокруг него одинарные кавычки. Это означает, что bash не будет расширять свое содержимое - вы фактически указываете grep искать регулярное выражение$1, а не для аргумента командной строки.Чтобы исправить это, используйте двойные кавычки вместо -
"$1"Первой команде grep говорят рекурсивно искать содержимое всех файлов в текущем каталоге (
-rи*подстановочные).В то же время вы передаете вывод
find -type fв grep - похоже, пытается сказать grep искать имена всех файлов.Это не сработает, потому что grep, как и большинство фильтров, не будет читать из стандартного ввода, если ему будет предоставлен один или несколько файлов для поиска. Я не знаю, что вы пытаетесь найти - имена файлов или содержимое файлов - поэтому выберите один:
Чтобы искать только имена файлов, сохраните канал, но удалите спецификацию файла:
find -type f | grep -i "$1" | ...Для поиска только содержимого файла удалите
find|вместо:grep -ir "$1" * | ...Можно объединить оба, явно указав grep файл "stdin":
find -type f | grep -i "$1" - * | ... find -type f | grep -i "$1" /dev/stdin * | ...(
/dev/stdinработает со всеми программами Linux, в то время как-это соглашение, используемое некоторыми программами, включая grep.)
Во второй команде grep регулярное выражение для поиска слишком широкое. (Помните, что это регулярное выражение, а не фиксированная строка.)
.svnбудет соответствовать даже что-то вродеnot-a-svn-file".Чтобы исключить
.svnкаталог, использоватьgrep -v "/\.svn/"вместо.При поиске содержимого файла (
grep -ir ...), еще лучше избавиться отgrep -vкомандовать целиком и добавить--exclude-dir=".svn"к первому.
Вы можете перестать читать на этом этапе
Приведенные ниже пункты являются хорошей практикой в сценариях sh.
functionключевое слово не нужно:ffind() { ...достаточно и работает во всех оболочках POSIX (покаfunction ffindне будет).В случае сбоя скрипта, программы или функции он должен вернуть статус "сбой" своему родителю. По соглашению, программы Unix считают
0означать "успех" и все остальное "неудача" (хотя есть и исключения из последнего).Чтобы вернуть статус явно, используйте
return <num>в функции (илиexit <num>в автономном сценарии):else echo "'$1' is not a valid resource" >&2 return 1 fiАналогично, сообщения об ошибках не следует смешивать с обычным stdout, а вместо этого записывать в stderr (fd # 2), используя
>&оператор перенаправления (см. пример выше). Таким образом, вы можете перенаправить нормальный вывод в файл (например,ffind intVal > results.txt) пока на экране все еще отображаются ошибки.
Фиксированный код
ffind()
{
if [ "$1" ] ; then
grep -ir --exclude-dir=".svn" "$1" .
else
echo "'$1' is not a valid resource" >&2
return 1
fi
}
Лучшие инструменты
ack утверждает, что "лучше чем grep". Бег ack "testing :" будет искать ваш исходный код и автоматически пропустить .svn и подобные каталоги.