web-dev-qa-db-ja.com

このソフトリンクが期待どおりに機能しないのはなぜですか?

bash4.3 # pwd
/bin
bash4.3 # ll sh
lrwxrwxrwx. 1   root    root    4   May 17 22:22 sh -> bash
bash4.3 # ll bash
-rwxr-xr-x. 1   root    root    1072056 May 17 22:22 bash
bash4.3 # bash
bash4.3 # sh
sh-4.3#

私のOSはFedora24(デフォルトのGNOMEバージョン)です。

例から、次のことがわかります。/binの下で、bashはバイナリ実行可能ファイルです。 shbashへのソフトリンクです。

したがって、私の知る限り、type bash and press entertype sh and press enterとまったく同じ結果をもたらすはずです。

type bash and press enterすると、期待どおり[root@localhost bin]#が得られます。

しかし、私がtype sh and press enterの場合、驚くべきことにsh-4.3#を取得します。

原因は何ですか?

11
xmllmx

これは文書化された機能です。

shという名前のシンボリックリンクを介してbashを実行すると、bashはsh互換モードで起動します。

man bashから:

Bashがshという名前で呼び出された場合、POSIX標準にも準拠しながら、shの履歴バージョンの起動動作を可能な限り模倣しようとします。対話型ログインシェル、または--loginオプションを指定した非対話型シェルとして呼び出されると、最初に/ etc/profileおよび〜/ .profileからコマンドをこの順序で読み取って実行しようとします。 --noprofileオプションを使用して、この動作を禁止できます。 shという名前の対話型シェルとして呼び出されると、bashは変数ENVを検索し、定義されている場合はその値を展開し、展開された値を読み取りおよび実行するファイルの名前として使用します。 shとして呼び出されたシェルは、他のスタートアップファイルからコマンドを読み取って実行しようとしないため、-rcfileオプションは効果がありません。 shという名前で呼び出された非対話型シェルは、他のスタートアップファイルを読み取ろうとしません。 shとして呼び出されると、bashはスタートアップファイルが読み取られた後にposixモードに入ります。

プログラムは、それを開始するために使用された名前をどのようにして知るのですか?

Cプログラムの場合は、argv[0]を検査できます。シェルまたはPerlスクリプトの場合、$0を検査できます。

例として、この単純なシェルスクリプトを考えてみましょう。

$ cat utc
#!/bin/sh
case "${0##*/}" in
        utc) date -u ;;
        et) TZ=US/Eastern date ;;
esac

$0は、スクリプトが呼び出された名前です。 ${0##*/}は、ディレクトリ名を削除してスクリプトが呼び出された名前です。

このシンボリックリンクを作成しましょう:

ln -s utc et

したがって、utcetはどちらも同じ実行可能ファイルを実行しますが、結果は異なります。 utcとして実行すると、ユニバーサル時間が出力されます。 etとして実行すると、米国東部時間を出力します。例えば:

$ utc
Wed Jul 20 18:14:18 UTC 2016
$ et
Wed Jul 20 14:14:20 EDT 2016
25
John1024