Значение последнего кода выхода скрипта Tcsh ($?) Сбрасывается - PullRequest
1 голос
/ 06 ноября 2019

Я использую следующий скрипт, используя tcsh. В моем цикле while я запускаю созданную мной программу на C ++ и в зависимости от определенных вещей будет возвращать другой код завершения. Хотя он возвращает код завершения 0, я хочу, чтобы скрипт увеличил счетчик и снова запустил программу.

#!/bin/tcsh

echo "Starting the script."
set counter = 0

while ($? == 0)
    @ counter ++
    ./auto $counter
end

Я убедился, что моя программа определенно возвращается с кодом завершения = 1 после определенной точки. Однако условие в цикле while по какой-то причине продолжает оцениваться как истинное и выполняется.

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

while ($return_code == 0)
    @ counter ++
    ./auto $counter
    set return_code = $?
end

Почему я не могу просто использовать $? напрямую? Выполняется ли другая операция под капотом между запуском моей пользовательской программы и проверкой состояния цикла, которое вызывает $? изменить значение?

Ответы [ 2 ]

1 голос
/ 06 ноября 2019

Немного более короткое / простое объяснение:

Напомним, что с помощью команды tcsh / csh EACH (включая встроенную оболочку) возвращается состояние. Следовательно, $? (псевдонимы $ status) обновляется с помощью операторов if, циклов for, назначений, ...

С практической точки зрения, лучше ограничить использование прямого использования $? в оператор if после выполнения команды:

do-something
if ( $status == 0 )
   ...
endif

Во всех других случаях фиксируйте состояние в переменной и используйте только эту переменную

do-something
something_status=$?
if ( $something_status == 0 )
   ...
endif

Для расширения $ statusдаже условный тест в операторе if изменит статус, поэтому следующий повторный тест на $ status никогда не достигнет значения $ status == 5, даже если что-то вернет статус 5

do-something
if ( $status == 2 ) then
  echo FOO
else if ( $status == 5 ) then
  echo BAR
endif
1 голос
/ 06 ноября 2019

Это странно.

Я изменил ваш пример на что-то, что, как мне кажется, более ясно иллюстрирует проблему. (Обратите внимание, что $? является псевдонимом для $status.)

#!/bin/tcsh -f

foreach i (1 2 3)
    false
    # echo false status=$status
end
echo Done status=$status

Вывод будет

Done status=0

Если я раскомментирую команду echo в цикле, выводэто:

false status=1
false status=1
false status=1
Done status=0

(Конечно, echo в цикле все равно нарушит логику, потому что команда echo завершается успешно и устанавливает $status в ноль.)

Я думаю , что происходит, что end, который завершает цикл, выполняется как оператор, и он устанавливает $status ($?) на 0.

Я вижу то же самоеПоведение с tcsh и bsd-csh.

Сохранение значения $status в другой переменной сразу после команды - хороший обходной путь - и, возможно, просто лучший способ сделать это, так как $status очень хрупкий, и почти буквально будет засорен, если вы посмотрите на него.

Обратите внимание, что я добавил опцию -f в строку #!. Это не позволяет tcsh получить исходные файлы инициализации (.cshrc или .tcshrc) и считается хорошей практикой. (Это не относится к sh / bash / ksh / zsh, которые присваивают совершенно другое значение -f.)

Отступление: я регулярно использовал tcsh в течение многих лет, оба в качестве интерактивного входа в системуоболочка и для скриптинга. Я бы не ожидал, что end установит $status. Это не первый раз, когда я должен был узнать, как tcsh или csh ведет себя методом проб и ошибок, и был удивлен результатом. Это одна из причин, по которой я переключился на bash для интерактивного использования и использования сценариев. Я не скажу вам сделать то же самое, но вы можете прочитать классику Тома Кристиансена " csh.whynot ".

...