Переменная Bash не работает - PullRequest
3 голосов
/ 10 июня 2011

У меня есть простой bash-скрипт, который является частью собственного веб-приложения, которое я разработал.

Его цель - автоматизировать удаление миниатюр изображений, когда исходное изображение было удалено пользователем.

Сценарий записывает некоторую базовую информацию о состоянии в файл /var/log/images.log

#!/bin/bash
cd $thumbpath
filecount=0
# Purge extraneous thumbs
find . -type f | while read file
do
  if [ ! -f "$imagepath/$file" ]
  then
    filecount=$[$filecount+1]
    rm -f "$file"
  fi
done
echo `date`: $filecount extraneous thumbs removed>>/var/log/images.log

Хотя скрипт правильно удаляет большие пальцы, он неправильно выводит количество удаляемых больших пальцев, он всегда показывает 0.

Например, просто вручную создав несколько потерянных миниатюр, а затем запустив мой сценарий, созданные вручную потерянные большие пальцы удаляются, но журнал показывает:

Чт, 9 июня 23:30:12 BST 2011: удалено 0 посторонних пальцев

Что я делаю неправильно, что мешает $ filecounter показывать число, отличное от нуля, когда файлы удаляются .

Я создал следующий bash-скрипт для проверки этого, и он отлично работает, выводя 0 затем 1:

#!/bin/bash
count=0
echo $count
count=$[$count+1]
echo $count

Edit:

Спасибо за ответы, но почему работает следующее

$ x=3
$ x=$[$x+1]
$ echo $x
4

... а также работает второй пример, но в первом сценарии он не работает?

Второе редактирование:

Это работает

count=0
echo Initial Value $count
for i in `seq 1 5`
do
  count=$[$count+1]
  echo $count
done
echo Final Value $count


Initial Value 0
1
2
3
4
5
Final Value 5

как и замена count=$[$count+1] на count=$((count+1)), но не в моем исходном скрипте.

Ответы [ 3 ]

6 голосов
/ 10 июня 2011

Вы используете неправильный оператор.Попробуйте вместо этого использовать $(( ... )), например:

$ x=4
$ y=$((x + 1))
$ echo $y
5
$

РЕДАКТИРОВАТЬ
Другая проблема, с которой вы сталкиваетесь, связана с трубой.Раньше сталкивался с этим (с ksh, но я не удивлюсь, обнаружив, что другие оболочки имеют такую ​​же проблему).Канал разветвляется на другой процесс bash, поэтому, когда вы выполняете инкремент, значение filcount увеличивается в subshell , который был разветвлен после канала.Это значение не передается обратно в вызывающую оболочку, так как подоболочка имеет свою собственную независимую среду (переменные среды наследуются в вызываемых процессах, но вызываемый процесс не может изменить среду вызывающего процесса).

В качестве примера, это демонстрирует, что filecount увеличивается с нуля:

#!/bin/bash

filecount=0
ls /bin | while read x
do
        filecount=$((filecount + 1))
        echo $filecount
done
echo $filecount

... так что вы должны увидеть увеличение filecount в цикле, но конечный filecount будет нулевым, потому что это эхо принадлежит основной оболочке, но разветвленныйsubshell (который состоит исключительно из цикла while).

Один из способов вернуть значение таков:

#!/bin/bash

filecount=0
filecount=`ls /bin | while read x
do
        filecount=$((filecount + 1))
        echo $filecount
done | tail -1`
echo $filecount

Это будет работать, только если вам все равноо любом другом выводе stdout в цикле, поскольку он отбрасывает все это, кроме последней строки, которую мы выводим (окончательное значение filecount).Это работает, потому что мы используем stdout и stdin для подачи данных обратно в родительскую оболочку.

В зависимости от вашей точки зрения, это либо неприятный хак, либо ловкий кусочек jiggery-pokery.Я оставлю вас, чтобы решить, что вы думаете: -)

2 голосов
/ 10 июня 2011

Если вы удалите конвейер в конструкцию while, вы удалите необходимость bash создать подоболочку.

Изменить это:

filecount=0
find . -type f | while read file; do
  if [ ! -f "$imagepath/$file" ]; then
    filecount=$[$filecount+1]
    rm -f "$file"
  fi
done
echo $filecount

к этому:

filecount=0
while read file; do
  if [ ! -f "$imagepath/$file" ]; then
    rm -f "$file" && (( filecount++ ))
  fi
done < <(find . -type f)
echo $filecount

Сложнее читать, потому что команда find в конце скрыта. Другая возможность:

files=$( find . -type f )
while ...; do
  : 
done <<< "$files"
1 голос
/ 10 июня 2011

Крис J совершенно прав в том, что вы используете неправильный оператор, а переменная область видимости переменной POSIX означает, что вы не можете получить окончательный счет таким образом.

В качестве примечания, при выполнении математических операций вы также можете рассмотреть возможность использования let оболочки bultin следующим образом:

$ filecount=4
$ let filecount=$filecount+1
$ echo $filecount
5

Также, если вы хотите, чтобы область видимости работала так, как вы ожидали, несмотря на этот конвейер, вы можете использовать zsh вместо bash. В этом случае это должно быть падение замены и работа как ожидалось.

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