4

Эй, ребята, у меня есть функция, которую я использую для поиска вещей, но, к сожалению, каждый раз, когда я передаю ей управляющий символ ($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 ответ1

8

Первый пример

$ 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. Слово '$1' заключено в одинарные кавычки. Это означает, что bash не будет расширять свое содержимое - вы фактически указываете grep искать регулярное выражение $1 , а не аргумент командной строки.

    Чтобы исправить это, используйте двойные кавычки - "$1"

  2. Первой команде 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.)

  3. Во второй команде grep регулярное выражение для поиска слишком широкое. (Помните, что это регулярное выражение, а не фиксированная строка.) .svn будет соответствовать даже чему-то вроде « not-a-svn-file ».

    Чтобы исключить каталог .svn , используйте вместо него grep -v "/\.svn/" .

    При поиске содержимого файла (grep -ir ...), даже лучше полностью избавиться от команды grep -v и добавить --exclude-dir=".svn" к первой.

Вы можете перестать читать на этом этапе

Приведенные ниже пункты являются хорошей практикой в сценариях sh .

  1. Ключевое слово function является необходимым: ffind() { ... достаточно и работает во всех оболочках POSIX (в то время как function ffind не будет).

  2. В случае сбоя скрипта, программы или функции он должен вернуть статус "сбой" своему родителю. По соглашению, программы Unix считают, что 0 означает "успех", а все остальное "неудача" (хотя есть и исключения из последних).

    Чтобы явно вернуть состояние, используйте return <num> в функции (или exit <num> в автономном скрипте):

    else
        echo "'$1' is not a valid resource" >&2
        return 1
    fi
    
  3. Аналогично, сообщения об ошибках не следует смешивать с обычным 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 и подобные каталоги.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .