Bashとkshパイプ

Bashとkshパイプ

kshスクリプトに問題があります。 FWIW私が克服できない問題は、このような構造を使用するときです。

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

私はしばしば私のスクリプトがwhileにパイプされたすべての行に対して繰り返されないことを発見します。これをテストするために、構造を次のように変更しました。

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

これは出力に多くの行があることを証明します。

また、do likeの直後に1行を追加します。

echo DEBUGGING: $VAR1  >&2

これはループが一度だけ実行されることを証明します。本当に混乱しています。

常に可能ではない解決策は次のとおりです。

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

それからこれはうまくいきます。ただし、私がこの構造を嫌うという事実は、コマンドラインから入力データ全体を拡張するという意味です(ハード制限を含む)。

bashはkshよりもこの種の仕事をうまく処理するようです。特に、これは読み取り呼び出しに失敗しましたが、ループの実行に長い時間がかかる場合は再試行しないことに関連している可能性があります。

しかし、Bashには「読み取り」機能が組み込まれていないようです。これは、ほとんどのスクリプトを再構築する必要があることを意味します。私はしばしば次のような大きな構造を使用します。

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

問題は、bash が期待どおりに FINAL_ANSWER の結果をできるだけ早く削除する /usr/bin/read を使用することです。確実な解決策は交換することです。

| read FINAL_ANSWER

そして

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

もしそうなら...これについてもっと詳しく説明できるスクリプトの専門家はいますか?実際のスクリプトはクライアント用に開発された機密ソリューションの一部であり、スクリプトの実際の詳細が問題を混乱させたくないため、ここに実際のスクリプトを意図的に公開していません。

私はしばしば「読みながら読み」フォーマットを使用します。一般的に動作します。実際、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

スクリプトを実行するたびにdowork1回実行されることがわかりました。dowork数秒以上かかると、正確に何かは問題ではありません。一種のシェルパイプタイムアウトが発生し、残りの入力が消えます。 Googleはdtkshがこの問題を解決できると言います。 (明らかに読み書きなどをやり直しますが、十分に読み取れません。)

/usr/st/bin/dtkshにdtkshがあることを確認しました。

誰ですか?私は知らないシェルを使うのが好きではありませんが、/usr/dt/bin/dtkshをインタプリタとして使用して、スクリプトの小さな部分を下付き文字に分割することをお勧めします。

どんな提案がありますか?

編集:ソルバーとしてkshのドロップイン代替としてbashを使用できない理由の例を提供するには、次のようにします。

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> #

答え1

あなたの質問は少し目的がありません。重要な部分であるkshとbashの違いについて答えます。

スクリプトに関して、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 では、2 番目の割り当てが親msgシェルで実行されるため、パイプの後ろにエフェクトが表示されます。他のシェルでは、この割り当てはサブシェルで実行されるため、最初の割り当ては親シェルに残ります。

回避策は、パイプラインで残りのスクリプトを実行することです。これは、データを読み取り、いくつかの処理を実行する一般的な慣用語です。

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

お持ちのようですkshのバグが発生しました。。バグレスバージョンにアップグレードすることをお勧めします。それが不可能な場合は試してください。ステファン・チャゼラスのソリューション。 bashでスクリプトを実行することはできますが、kshを直接置き換えるのではなく、bashにないksh機能がたくさんあります(その逆も同様です)。 Bashとkshは、POSIXコアと他のコア機能(特に配列[[ … ]]と宣言された関数のローカル変数)でのみ互換性がありますtypeset

として呼び出されると、kshbashよりもkshに近づくように動作するzshを試すこともできます。それにもかかわらず、非互換性が発生する可能性があります。

関連情報