Условное соединение Bash, с подстановочными знаками и проверкой существования файла - PullRequest
5 голосов
/ 25 августа 2010

Я освоил основы составных условных выражений Bash и прочитал несколько различных способов проверки существования файла с подстановочными символами, но этот способ ускользает от меня, поэтому я решил, что попросу помощи ... 1001 *

Мне нужно: 1.) Проверьте, существует ли какой-либо файл, соответствующий шаблону А ТАКЖЕ 2.) Убедитесь, что текст в другом файле существует.

Я знаю, что есть много способов сделать это, но у меня действительно нет знаний, чтобы расставить приоритеты (если у вас есть эти знания, мне было бы интересно также прочитать об этом).

Первое, что пришло в голову, это использовать find для # 1 и grep для # 2

Так что-то вроде

if [ `grep -q "OUTPUT FILE AT STEP 1000" ../log/minimize.log` ] \
      && [ `find -name "jobscript_minim\*cmd\*o\*"` ]; then
   echo "Both passed! (1)"
fi

Это терпит неудачу, хотя с любопытством:

if `grep -q "OUTPUT FILE AT STEP 1000" ../log/minimize.log` ;then
   echo "Text passed!"
fi
if `find -name "jobscript_minim\*cmd\*o\*"` ;then
   echo "File passed!"
fi

оба прохода ...

Я немного прочитал и видел, как люди говорили о проблеме множественных имен файлов, совпадающих с подстановочными знаками в операторе if. Каково лучшее решение для этого? (отвечая на мой вопрос, я предположил, что вы также разбираетесь с этим вопросом в процессе)

Есть идеи / решения / предложения?

Ответы [ 3 ]

11 голосов
/ 25 августа 2010

Давайте разберемся, почему ваша попытка не удалась первой:

if [ `grep -q …` ]; 

Эта команда запускает команду grep между обратными галочками и интерполирует выходные данные внутри условной команды.Поскольку grep -q не производит никакого вывода, это как если бы вы написали if [ ];

Условное условие должно проверять код возврата grep, а не что-либо о его выводе.Поэтому его следует просто записать как

if grep -q …;

Команда find возвращает 0 (т. Е. True), даже если ничего не находит, поэтому этот метод не будет работать.Что будет работать, так это проверить, является ли его вывод пустым, путем сбора выходных данных, сравнивая его с пустой строкой:

if [ "$(find …)" != "" ];

(эквивалентный тест if [ -n "$(find …)" ].)

Обратите внимание на двавещи здесь:

  • Я использовал $(…), а не backticks.Они эквивалентны, за исключением того, что обратные галочки требуют странных кавычек внутри них (особенно если вы пытаетесь их вложить), тогда как $(…) прост и надежен.Просто используйте $(…) и забудьте о обратных чертах (за исключением того, что вам нужно написать \` внутри двойных кавычек).

  • Двойные кавычки вокруг $(…).Это действительно важно.Без кавычек оболочка прервала бы вывод команды find на слова.Если find печатает, скажем, две строки dir/file и dir/otherfile, мы хотим, чтобы выполнялось if [ "dir/file dir/otherfile" = "" ];, а не if [ dir/file dir/otherfile = "" ];, что является синтаксической ошибкой.Это общее правило программирования оболочки: всегда ставит двойные кавычки вокруг переменной или подстановки команды .(Подстановка переменных $foo или ${foo}; подстановка команд $(command).)


Теперь давайте посмотрим ваши требования.

  1. Проверьте, существует ли какой-либо файл, соответствующий шаблону

    Если вы ищете файлы в текущем каталоге или в любом каталоге под ним рекурсивно, тогда find -name "PATTERN" правильно.Однако, если дерево каталогов может стать большим, это неэффективно, потому что оно может потратить много времени на печать всех совпадений, когда мы заботимся только об одном.Простая оптимизация состоит в том, чтобы сохранить только первую строку, добавив в head -n 1;find прекратит поиск, как только поймет, что head больше не интересуется тем, что он говорит.

    if ["$ (find -name" jobscript_minim cmd o "|head -n 1) "! =" "];

    (обратите внимание, что двойные кавычки уже защищают символы подстановки от расширения.)

    Если вы ищете только файлы в текущем каталогеПредполагая, что у вас есть GNU find (как в случае Linux, Cygwin и Gnuwin32), простое решение состоит в том, чтобы сказать, что он не должен рекурсировать глубже, чем текущий каталог.-name "jobscript_minim * cmd * o *") "! =" "];

    Существуют и другие решения, которые более переносимы, но их сложнее написать.

  2. Убедитесь, что текст в другом файле существует.

    У вас уже есть правильная команда grep.Обратите внимание, что если вы хотите искать буквальную строку, вы должны использовать grep -F;если вы ищете регулярное выражение, grep -E имеет более разумный синтаксис, чем обычный grep.

Соберите все вместе:

if grep -q -F "OUTPUT FILE AT STEP 1000" ../log/minimize.log &&
   [ "$(find -name "jobscript_minim*cmd*o*")" != "" ]; then
  echo "Both passed! (1)"
fi
0 голосов
/ 19 мая 2011
for i in filename*; do FOUND=$i;break;done
if [ $FOUND == 'filename*' ]; then
echo “No files found matching wildcard.”
else
echo “Files found matching wildcard.”
fi
0 голосов
/ 25 августа 2010

Баш 4

shopt -s globstar
files=$(echo **/jobscript_minim*cmd*o*)
if grep -q "pattern" file && [[ ! -z $files ]];then echo "passed"; fi
...