POSIXLY_CORRECT とは何ですか? また、何がそれを変更するのですか (Centos 8.4)?

POSIXLY_CORRECT とは何ですか? また、何がそれを変更するのですか (Centos 8.4)?

GitHub のスクリプトを使用してテストしていますmigrate2rocky.sh:

https://github.com/rocky-linux/rocky-tools/blob/main/migrate2rocky/migrate2rocky.sh

昨日これをテストしたところ、問題なく動作しました。今日はスナップショットに戻して再度実行しました。今回は最初のチェックでスクリプトが失敗しました。

if [ -n "$POSIXLY_CORRECT" ] || [ -z "$BASH_VERSION" ]; then
    printf '%s\n' "bash >= 4.0 is required for this script." >&2
    exit 1
fi

具体的には、テストに失敗します $POSIXLY_CORRECT(検証のためにコード スニペットを個別に実行しました)。実行中の bash バージョンを確認しました。

[user@server ~]$ rpm -qa | grep bash
bash-completion-2.7-5.el8.noarch
bash-4.4.20-1.el8_4.x86_64
[user@server ~]$ echo $BASH_VERSION
4.4.20(1)-release
[user@server ~]$ echo $POSIXLY_CORRECT

[user@server ~]$

私の知る限り、POSIX は UNIX 系 OS 間でのアプリケーションの移植性を容易にするための標準セットです。

スクリプトが機能しなくなった理由を説明するために、サーバーに変更は加えられていません。まだスクリプトを使用していないサーバーでスクリプトをテストしましたが、同じ問題が発生します。

サーバーはすべて CentOS 8.4 です。

$POSIXLY_CORRECTが何をするのか、また昨日は問題なかったのになぜ今はエラーになるのかがわかりません。

何か質問があればお知らせください。本当に困惑しています。


sudo bash -x migrate2rocky.shコマンドの出力:

[user@server ~]$ sudo bash -x migrate2rocky.sh
+ '[' -n '' ']'
+ '[' -z '4.4.20(1)-release' ']'
+ ((  BASH_VERSINFO < 4  ))
+ ((  EUID != 0  ))
+ logfile=/var/log/migrate2rocky.log
+ truncate -s0 /var/log/migrate2rocky.log
+ exec
++ tee -a /var/log/migrate2rocky.log
++ tee -a /var/log/migrate2rocky.log
+ errcolor=
+ blue=
+ nocolor=
+ export LANG=en_US.UTF-8
+ LANG=en_US.UTF-8
+ shopt -s nullglob
+ SUPPORTED_MAJOR=8
+ SUPPORTED_PLATFORM=platform:el8
++ arch
+ ARCH=x86_64
+ gpg_key_url=https://dl.rockylinux.org/pub/rocky/RPM-GPG-KEY-rockyofficial
+ gpg_key_sha512=88fe66cf0a68648c2371120d56eb509835266d9efdf7c8b9ac8fc101bdf1f0e0197030d3ea65f4b5be89dc9d1ef08581adb068815c88d7b1dc40aa1c32990f6a
+ declare -A repo_urls
+ repo_urls=([rockybaseos]="https://dl.rockylinux.org/pub/rocky/${SUPPORTED_MAJOR}/BaseOS/$ARCH/os/" [rockyappstream]="https://dl.rockylinux.org/pub/rocky/${SUPPORTED_MAJOR}/AppStream/$ARCH/os/")
+ unset CDPATH
+ convert_info_dir=/root/convert
+ unset convert_to_rocky reinstall_all_rpms verify_all_rpms update_efi
+ noopts=0
+ getopts hrVR option
+ ((  ! noopts  ))
+ usage
+ printf '%s\n' 'Usage: migrate2rocky.sh [OPTIONS]' '' Options: '-h Display this help' '-r Convert to rocky' '-V Verify switch' '   !! USE WITH CAUTION !!'
Usage: migrate2rocky.sh [OPTIONS]

Options:
-h Display this help
-r Convert to rocky
-V Verify switch
   !! USE WITH CAUTION !!
+ exit 1
[user@server ~]$

不思議なことに、昨日行ったように、 " " コマンドではなく " " コマンドで実行すると、上記のようにコマンドが機能します (テストを通過して 、とPOSIXLY_CORRECTの値をテストします) 。BASH_VERSIONEUIDbashsh

答え1

エラー メッセージは、リリース 4.0 より新しいシェルのリリースでスクリプトを実行していないことを示していますbash。おそらく、スクリプトは、bashシェルが実装する機能に依存しており、その機能は Unix シェル言語の POSIX 標準で規定されている機能セットとは異なるか、その機能を拡張しています。

質問の最後では、 を使用して実行したことが確認されていますがsh、これはシステム上では 以外のシェルである可能性があります。 が偽装されている bash場合でも、POSIX モードで実行されているシェルになります。shbash

スクリプトを を使用して実行することを検討してくださいbash。または、スクリプトの#!先頭に 行がある場合は、スクリプトを実行可能にして ( を使用してchmod +x scriptname)、 のように実行します./scriptname

環境POSIXLY_CORRECT変数は、ツールが POSIX 標準で規定されている動作とは異なる動作を実装する場合に、ユーティリティが動作を選択するのに役立つ変数です。

POSIX モードでは、シェルbashの動作が若干異なります (つまり、set -o posixが有効になっている場合、またはシェルが として起動されている場合sh)。違いについては、「Bash POSIX モードマニュアルの「」を参照してくださいbash

答え2

Kusalananda の回答をいくつかの文脈的詳細で補足します。

からリンクされたGithub URLを見ると、スクリプトの最初の行が であることがわかります#!/bin/bash。この行は、スクリプトに使用されるインタープリタを示しています。この場合はシェルですbash。つまり、このスクリプトはbashシェルで実行されることを意図しています。

その理由は、35 行目と 26 行目のコメントで明らかになっています。

# These checks need to be right at the top because we start with bash-isms right
# away in this script.

「Bash-isms」はbashシェルに固有の機能です。配列はその良い例です。bashシェルが使用されていることを確認するために、2 つの条件がチェックされます。

このBASH_VERSION変数は、シェルによって設定される特別な変数ですbash。他のシェルはこの変数を設定しないので、定義されていることを確認するだけで続行できます。

この変数は、POSIX モードと呼ばれる別のモードで実行できるPOSIXLY_CORRECTため、役立ちます。このモードは、他のシェル、さらには古いシェルとの互換性を確保するために存在します。この互換性を確保するために、新しい機能のいくつかがオフになっています。繰り返しますが、これによってスクリプトが壊れるため、POSIX モードのインスタンスからスクリプトを実行することはできません。これが、チェックが反転されている理由です。つまり、チェックは設定しないでください。POSIX モードで実行するときに設定されます。bashbashbashPOSIXLY_CORRECTbash

質問で既に指摘されているように、意図したとおりにスクリプトを実行すると、定義されているかどうかの/bin/bashチェックに問題なく合格します。BASH_VERSIONPOSIXLY_CORRECT

関連情報