POSIXシェルスクリプトとPOSIXユーティリティでPOSIXロケールが提供されていないことをどのようにポータブルで検出できますか?

POSIXシェルスクリプトとPOSIXユーティリティでPOSIXロケールが提供されていないことをどのようにポータブルで検出できますか?

Termuxは、これまでPOSIXロケールのない唯一のPOSIX環境です。結果は次のとおりです。

awk 'BEGIN{for(i=1;i<256;i++)printf"%c",i;}'

Termuxでnull以外のすべてのバイトを出力するのではなく、実際にはGNU awkであり、これはロケールによって異なります。しかしこの-b選択は成功をもたらす。

存在するShellShoccar-jpn/kotoriotokoに関する問題(日本語) 日本語やその他のUTF-8文字列を適切に処理する方法について議論していますが、現在の議論は互換性を超えています。 GAWK は使用できますが、POSIX ロケールと UTF-8 ロケールは使用可能かどうかは考慮しません。いいえ。 。それでは、GAWKではなくawkはどうですか?おそらくawk '...' | xargs -I x printf x最も互換性のあるアイデアでしょう。

まず、POSIXロケールが利用できないことをどのように検出しますか?これまで私が思いついたことは次のとおりです(まだテストしていません)(また、TermuxはlocaleコマンドやPOSIXロケールを提供せず、単に使用できることも発見しましたen_US.UTF-8)。

# 1
POSIX_LOCALE_AVAILABLE=no
type locale >/dev/null 2>&1 && {
   locale -a |
   grep -qE '^(C|POSIX)$' &&
   POSIX_LOCALE_AVAILABLE=yes
}

# 2
export LC_ALL=C
POSIX_LOCALE_AVAILABLE=no
case "$LC_ALL" in ('C')
   POSIX_LOCALE_AVAILABLE=yes
;;esac

# 3
POSIX_LOCALE_AVAILABLE=no
case "$(
   LC_ALL=C awk 'BEGIN{for(i=1;i<256;i++)printf"%c",i;}' |
   od -A n -t x1 -v |
   tr ABCDEF abcdef |
   tr -Cd abcdef1234567890
)" in ("$(
   awk 'BEGIN{for(i=1;i<256;i++)printf"%02x",i;}'
)")
   POSIX_LOCALE_AVAILABLE=yes
;;esac

しかし、すべてのPOSIX環境に適用されますか?そうでない場合、他のオプションはありますか?

答え1

どうですか(他のロケールも必要です:この場合はUTF-8):

#!/bin/sh
export LC_ALL=C
# alternatively:
# a="$(printf \\343\\201\\202)" # actually あ
# case "$(mkdir "$a" && ls -dq "$a" && rmdir "$a")" in ("$a")
# end alternative
case "$(mkdir あ && ls -dq あ && rmdir あ)" in (あ)
  echo NO
;;(*'?'*)
  echo YES
;;(*)
  echo WTF
;;esac

上記のスクリプトは、Cロケールが使用可能かどうかを出力します。

ls -q非ASCII文字は次のように置き換える必要があります。 ingが実際にロケールを変更しない場合、?この操作は失敗するはずです。export

上記のコメントされていないバージョンは、次の場合に失敗する可能性があります。ヤッシュユーザーであり、LANGUTF-8ではありません。コメントをつけてみてください(動作しているかわかりません)。

(PS. yashバージョン2.51で動作、. the_script_above.sh失敗)

答え2

@schilyがコメントしたようにどうですか?

if command -p getconf PATH | grep .; then
   : 'LC_ALL=C is available'
else
   : 'LC_ALL=C is not available'
fi

Termuxを使ってみましたが、Arch GNU / Linuxが動作しているようです。

関連情報