Первый пример
$ ffind $intVal
'' is not a valid resource
Это не работает, потому что $foo
является синтаксисом для переменных, и у вас нет переменной с именем intVal
set, поэтому $intVal
преобразуется в пустую строку. Поскольку переменная также не заключена в кавычки , аргументы вообще не передаются в ffind
.
Чтобы исправить это, избегайте $
- \$intVal
(обратный слеш) или '$intVal'
(в одинарных кавычках).
Если у вас действительно есть переменная с именем intVal
, вместо этого поместите ее в двойные кавычки - "$intVal"
- это расширит значение переменной, но не разделит ее.
Обратите внимание, что в bash нет такой вещи, как "передать по ссылке". Существует только передача по значению и (хитрая) передача по имени.
Второй пример
$ ffind "testing :"
bash: [: testing: unary operator expected
'testing :' is not a valid resource
Это не работает, потому что вы забыли поместить кавычки около $1
в строку if [ $1 ]
, поэтому он может быть разбит на слова , и три аргумента передаются в [
builtin:
- "
[
"
- "
testing
"
- "
:
"
- "
]
"
вместо ожидаемых двух:
- "
[
"
- "
testing :
"
- "
]
"
Пример # 1 также зависит от этого, так как [ $1 ]
распадается на ([
]
") , а не [
"",
Пример № 1 работает случайно, хотя, по-видимому, ]
является действительным. (Я этого не знал ...)
Чтобы решить эту проблему, поместите двойные кавычки около $1
- [ "$1" ]
.
Примечание. Хотя [
является стандартным, есть также специфический для bash оператор [[
, который на самом деле имеет правила синтаксического анализа, отличные от остальной части кода - в частности, он не разделяет расширенные переменные. В 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
и подобные каталоги.