Функция 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
и подобные каталоги.