Трубы Bash vs ksh

Я застрял с некоторыми проблемами с моими скриптами в ksh. FWIW проблема, которую я не могу преодолеть, заключается в том, что когда я использую такую ​​структуру, как эта

command | while read VAR1 do many.commands using $VAR1 done 

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

 command > /tmp/tempfile cat -n /tmp/tempfile >&2 cat /tmp/tempfile | while read VAR1 etc 

Это доказывает, что на выходе имеется много строк.

Далее я добавляю дополнительную строку сразу после do, например

 echo DEBUGGING: $VAR1 >&2 

Это доказывает, что цикл работает только один раз. Я действительно в тупике.

Одно решение, которое не всегда жизнеспособно, – это сделать

 for X in $(cat /tmp/tempfile ) do ... done 

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

Похоже, что bash лучше, чем ksh при работе с подобными вещами. В частности, похоже, что это может быть связано с провалом чтения, но не повторением, если цикл занимает много времени для запуска.

Однако кажется, что bash не имеет встроенного «чтения», что означает, что многие мои скрипты нужно будет переписать. I OFTEN используют большие структуры, такие как

 command1 | command2 | while read SOMEVAR; do awk -F: "... long awk program" | sed "long sed program" ; done | sort -u | tail -1 | read FINAL_ANSWER 

Проблема в том, что bash использует / usr / bin / read, который, как ожидается, отбрасывает результат FINAL_ANSWER так быстро, как он получает. Очевидным обходным решением является замена

 | read FINAL_ANSWER 

с

 > /tmp/final_answer && FINAL_ANSWER="$(cat /tmp/final_answer)" 

Итак … Любые писатели-сценаристы здесь могут пролить свет на это? Я намеренно не публиковал свои реальные сценарии здесь, потому что они являются частью чувствительного решения, разработанного для клиента, и потому, что я не хочу, чтобы фактическая деталь скриптов путала проблему.

Я использую формат «while read» OFTEN. Обычно это работает. У меня на самом деле никогда не было проблем с этим в течение 25 лет работы с оболочкой. Теперь у меня проблемы. Очень расстраивает. Недоумение.

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

 command | while read NEXT_ONE DONEFLAG do if [ $DONEFLAG = "yes" ] then echo Already completed work for $NEXT_ONE else dowork $NEXT_ONE && set_flag $NEXT_ONE fi done 

Оказывается, что при каждом запуске скрипта он выполняет dowork один раз. На самом деле не имеет значения, что такое dowork , если это занимает больше нескольких секунд. Происходит какой-то тайм-аут оболочки, и остальная часть входа затем исчезает. Google сообщает мне, что dtksh может решить эту проблему (видимо, он будет повторять чтение / запись или что-то еще, я недостаточно читал)

Я вижу, что dtksh существует в / usr / st / bin / dtksh

Кто это? Мне не нравятся использование оболочек, которые я не знаю, но, возможно, стоит разделить небольшие части скриптов на суб-скрипты с помощью / usr / dt / bin / dtksh в качестве интерпретатора.

Любой совет?

EDIT: Предоставление примера того, почему я не могу использовать bash в качестве замены для замены ksh как интерпретатора:

 sol10-primary> # cat test.sh #!/bin/ksh echo hello| read VAR1 echo $VAR1 sol10-primary> # ./test.sh hello sol10-primary> # sed 's/ksh/bash/' <test.sh >test2.sh sol10-primary> # chmod +x test2.sh sol10-primary> # ./test2.sh sol10-primary> # 

Ваш вопрос немного бессвязно. Я отвечу на то, что, кажется, центральная часть, на разницу между ksh и bash, которую вы наблюдаете.

Вы столкнулись с вероятностью # 1 несовместимости между ksh и bash, когда дело доходит до скриптов. ATT ksh (оба ksh88 и ksh93) и zsh выполняют последнюю (самую правую) команду в конвейере родительской оболочки, тогда как другие оболочки (Bourne, ash, bash, pdksh, mksh) выполняют все команды, включая последнюю в подоболочке ,

Вот простая тестовая программа:

 msg="a subshell" true | msg="the parent shell" echo "This shell runs the last command of a pipeline in $msg" 

В ATT ksh и zsh второе назначение для msg выполняется в родительской оболочке, поэтому эффект видим после конвейера. В других оболочках это назначение выполняется в подоболочке, поэтому первое назначение сохраняется в родительском.

Обходным путем является выполнение остальной части сценария в конвейере. Это распространенная идиома для чтения данных и последующей обработки:

 output_some_stuff | { var= while IFS= read -r line; do var=$(process "$line") done use "$var" } 

Кажется, вы столкнулись с ошибкой ksh . Я рекомендую обновить до не-багги. Если это невозможно, попробуйте использовать Stephane Chazelas . Хотя вы можете попробовать запустить свои скрипты в bash, это не (и не претендует на роль) замена для ksh; есть много особенностей ksh, которые bash не имеет (и наоборот). Bash и ksh совместимы только в их ядре POSIX и некоторых других центральных функциях (в частности, в массивах, [[ … ]] и локальных переменных в объявленных typeset ).

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