KEY=VALUE
単一変数を連想配列(1行に1つずつ)として使用するシェルスクリプトがあります。
スクリプトの実行中、変数は項目を追加、削除、または変更するために操作されます。
追加:
VARIABLE="$(printf "%s\n%s" "$VARIABLE" "KEY=VALUE")"
調整:
VARIABLE="$(printf "%s\n" "$VARIABLE" | sed -E "s,^(KEY=).*$,\1VALUE,")"
削除する:
VARIABLE="$(printf "%s\n" "$VARIABLE" | grep -E -v "^KEY=.*$")"
端末で実行されている場合(または以前のシステムのサービスとして)システムinitスクリプトを介して)うまく実行されますが、サービスとして実行されるときシステムしばらくすると、スクリプトはログにエラーメッセージを表示し始めます。
sh: printf: I/O error
多くの試行錯誤の後、スクリプトのどのコマンドがこれらのエラーを生成したのかわかりませんでしたが、変数の長さが8000バイトに達した場合(8192と推測されますが、正確には不明)、まさに私が行全体を追加してからです。
変数の長さが8192バイトに達するたびに、配列内で最も古い項目を切り取るルーチンを実装しているため、変数の長さが問題であると確信しています。スクリプトはsystemd
エラーなしで長時間実行されます。一部の情報が失われるため理想的ではありません。
シェルスクリプトの最大変数長に関する情報をオンラインで検索しましたが、有用な情報が見つかりませんでした。
dash
マニュアルページには最大変数長は記載されていません。GNU sed ドキュメント説明する:
ポータブルで使いたい人はsedスクリプトでは、一部の実装では、行の長さ(パターンと予約済みスペース)を4000バイト以下に制限することが知られています。これPOSIX標準要件は以下に準拠しています。sed実装は少なくとも8192バイトの行長をサポートする必要があります(SHOULD)。GNU sed可能な限り行の長さには基本的な制限はありません。malloc()より多くの(仮想)メモリを使用すると、必要に応じてラインを提供または構築できます。
...しかし、これは次に当てはまります。ワイヤー全文長ではない長さ(1行に80文字以下)
とにかく、エラーはスクリプトが実行されているときにのみ表示されるため、systemd
ユニットファイルでLimitMSGQUEUE
および/または増やそうとしましたが、LimitSTACK
役に立ちませんでした。 (メッセージキューやプロセススタックの概念を完全に理解していないため、これは盲目的な推測です。ただし、表示された数字はsystemctl show
8 KBほどであるようです。メモリ(LimitRSS
、、、LimitAS
)に関する他のすべての制限はLimitMEMLOCK
十分に高いようです。 )次に何をすべきかわかりません。
systemd
変数の長さが8KBを超えるときにこのスクリプトを正しく実行するにはどうすればよいですか?
答え1
答えよりは診断に近い…
私のシステムで以下を実行してください。dash
v0.5.8-2.10、可変長は少なくともかなり大きくてもよい。2^30性格。${x}
文字の長さが薬を超えるまで変数の長さを2倍にするデモです${#x}
。25%利用可能なメモリ(設定:アドホック furp
機能):
最初のスタートdash
:
dash
次に、dash
(で)次のコードを実行します。
furp() { free | { read z; read a b c d; echo $((100*$c/$b)) ; } }
x=1
while [ `furp` -lt 25 ] ; do
x="${x}${x}"; echo ${#x}
done | tail -1
出力(私のシステムでは利用可能なメモリによって異なります):
1073741824
上記のコードをスクリプトに入れたら、systemd
同じ環境で実行して出力を確認してください。
答え2
(表現力が不足して)
「sh:printf:I / O error」は、スクリプトがsystemdsh
ではなく使用されたことを意味しますdash
。おそらくこれはdiffが動作する場所でしょうか?