Изменение переменной оболочки в цикле while не работает должным образом - PullRequest
1 голос
/ 30 апреля 2009

Это очень простой bash-скрипт, который я написал:

#!/bin/bash

ITEM_LIST=items.txt
LOG_FILE=log.log

TOTAL_ITEMS=$(wc -l ${ITEM_LIST} | awk '{ print $1 }')
let NOT_FOUND=0

cat ${ITEM_LIST} | while read item; do

    grep "${item}" ${LOG_FILE} > /dev/null
    FOUND=${?}
    if [ ${FOUND} -ne 0 ]; then
        let NOT_FOUND=NOT_FOUND+1
        echo "Item not found [${item}] Item not found number: ${NOT_FOUND}"
    fi

done

echo "Total items: ${TOTAL_ITEMS}"
echo "Total not found items: ${NOT_FOUND}"

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

Рассмотрим два примера файлов:

items.txt

first item
second item
third item
fourth item
fifth item

log.log

blahblah blah blah first item blah blah blah
second blah blah item
blah third item blah

Вывод скрипта:

[17:46:38]:/cygdrive/c/Temp/qpa# ./script2.sh 
Item not found [second item] Item not found number: 1
Item not found [fourth item] Item not found number: 2
Total items: 4
Total not found items: 0

Вопрос:

Почему скрипт печатает "Всего не найдено элементов: 0"? Он печатает текущую сумму по каждому эхо в цикле (обе переменные NOT_FOUND).

Есть ли плохие практики в этом сценарии оболочки? Где и почему?

Ответы [ 2 ]

6 голосов
/ 30 апреля 2009

Труба, которую вы используете здесь:

cat ${ITEM_LIST} | ...

После этого выполнит цикл while в под-оболочке. Но это означает, что переменная NOT_FOUND не будет обновлена ​​в родительской оболочке, а только в под-оболочке, в которой вы выполняете цикл.

Включите команды echo в конце внутри этого экземпляра вложенной оболочки:

cat ${ITEM_LIST} | { 
  while read item; do
    grep "${item}" ${LOG_FILE} > /dev/null
    FOUND=${?}
    if [ ${FOUND} -ne 0 ]; then
        let NOT_FOUND=NOT_FOUND+1
        echo "Item not found [${item}] Item not found number: ${NOT_FOUND}"
    fi
  done

  echo "Total items: ${TOTAL_ITEMS}"
  echo "Total not found items: ${NOT_FOUND}"
}

Эта проблема также объясняется в элементе часто задаваемых вопросов Bash . Надеюсь это поможет.

Как часто задаваемые вопросы объясняют, в этом конкретном случае вы также можете переписать его так, чтобы оно гласило:

while read item; do
    grep "${item}" ${LOG_FILE} > /dev/null
    FOUND=${?}
    if [ ${FOUND} -ne 0 ]; then
        let NOT_FOUND=NOT_FOUND+1
        echo "Item not found [${item}] Item not found number: ${NOT_FOUND}"
    fi
done < ${ITEM_LIST}

Предпочитайте второй вариант в этом случае, поскольку он избавится от одного "бесполезного использования кошки":)

0 голосов
/ 30 апреля 2009

Используйте expr , чтобы сделать математику

NOT_FOUND=0; NOT_FOUND=`expr ${NOT_FOUND} + 1`; echo ${NOT_FOUND}

1

@ litb верно, вам нужно обновить NOT_FOUND в вашем основном скрипте, а не в вспомогательной оболочке, порожденной командой pipe.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...