Присвоение результата "теста" переменной
Я пишу script, где мне нужно использовать вывод теста файла в нескольких местах, в том числе внутри оболочки. Я хотел бы присвоить существование файла переменной оболочки, например: file_exists=[ -f $myfile ]
.
Просто чтобы убедиться, что у меня есть мои базы, я начинаю с касания файла и тестирования его существования:
file='a'
touch $file
if [ -f $file ]
then
echo "1 -- '$file' exists"
fi
Вывод:
1 -- 'a' exists
Файл был создан успешно - никаких сюрпризов, но, по крайней мере, я знаю, что я не имею никаких проблем с разрешениями или что-то еще.
Далее я проверяю, чтобы я мог хранить логическое выражение в переменной:
mytest=/bin/true
if $mytest
then
echo "2 -- \$mytest is true"
fi
Вывод:
2 -- $mytest is true
Итак, у меня есть основные понятия - условные выражения должны выдавать тот же результат, что и /bin/true
или /bin/false
... но это не то, что я вижу:
mytest=[ -f $file ]
if $mytest
then
echo "3 -- \$mytest is true [expect true]"
else
echo "3 -- \$mytest is false [expect true]"
fi
Это не выполняется со следующей ошибкой:
-f: command not found
Я получаю то же сообщение об ошибке, если я использую test -f $file
, а не [ -f $file ]
.
Если я поместил пробел перед [
, ошибка исчезнет...
mytest= [ -f $file ]
if $mytest
then
echo "4 -- \$mytest is true [expect true]"
else
echo "4 -- \$mytest is false [expect true]"
fi
Выход кажется правильным:
4 -- $mytest is true [expect true]
... но если я удалю файл, я должен получить противоположный результат:
rm $file
mytest= [ -f $file ]
if $mytest
then
echo "5 -- \$mytest is true [expect false]"
else
echo "5 -- \$mytest is false [expect false]"
fi
... и я не делаю:
5 -- $mytest is true [expect false]
Чтобы быть справедливым, я ожидал, что пространство испортится с истинным значением:
mytest= /bin/false
if $mytest
then
echo "6 -- \$mytest is true [expect false]"
else
echo "6 -- \$mytest is false [expect false]"
fi
Выходы:
6 -- $mytest is true [expect false]
Итак, как я могу сохранить вывод из test
встроенного в переменную оболочки?
Ответы
Ответ 1
Как описано в других документах, использование строки "true" - это красная селедка; это не является подходящим способом хранения логических значений в сценариях оболочки, поскольку его оценка означает динамическое выключение команды, а не просто проверку сохраненного значения с помощью встроенных оболочек оболочки, жестко закодированных в вашем script.
Вместо этого, если вы действительно должны сохранить статус выхода, сделайте это как числовое значение:
[ -f "$file" ] # run the test
result=$? # store the result
if (( result == 0 )); then # 0 is success
echo "success"
else # nonzero is failure
echo "failure"
fi
Ответ 2
Вам нужно процитировать пробелы:
mytest='[ -f $file ]'
if $mytest; then echo yes; fi
Однако это чрезвычайно хрупкое и потенциально небезопасное. См. http://mywiki.wooledge.org/BashFAQ/050 для подробного обсуждения и некоторых лучших способов добиться чего-то подобного.
Если вы хотите инкапсулировать сложный фрагмент кода, обычно это способ:
mytest () { [ -f "$file" ]; }
if mytest; then echo yes; fi
Если вы хотите запустить код один раз и сохранить его результат, чтобы вы могли его изучить позже, я бы перефразировал его следующим образом:
if [ -f "$file" ]; then
mytest=true
else
mytest=false
fi
if $mytest; then echo yes; fi
Ответ 3
mytest=/bin/true
хранит строку /bin/true
в переменной $mytest
.
mytest=[ -f $file ]
устанавливает переменную $mytest
в значение [
для продолжительности команды -f $file ]
(которая по мере того, как ваш вывод указывает на ошибку, поскольку нет команды -f
).
mytest= [ -f $file ]
(как и выше) устанавливает значение переменной $mytest
пустым в течение команды [ -f $file ]
(и возвращает все [
).
mytest= /bin/false
это то же самое, что и в приведенном выше случае, только команда запускается /bin/false
.
Если вы хотите сохранить код возврата из команды в переменной, вы можете сделать
/bin/true
ret=$?
если вы хотите сохранить вывод из команды в переменной, которую вы можете сделать
out=$(/bin/true)
(хотя при /bin/true
эта переменная будет пуста, так как она не выводит текст.
Для вашего случая вам нужна прежняя модель $?
.
Кроме того, использование set -x
(и/или set -v
) в ваших скриптах могло помочь вам диагностировать это.
Ответ 4
Старый, но оставил это здесь для справки людям, которым это может понадобиться. Не самое красивое решение, но оно работает в bash:
mytest=$( [ -f $file ] ; echo $? )
Более переносимый, используя команду test и обратные ссылки:
set mytest='test -f $file ; echo $?'
В подпроцессе (<!> Загрузка системы) выполняется оценка условия, а затем результат отражается в выводе, который захватывается переменной $ mytest.