コマンドオプションがコマンド内で実行されている他のスクリプトを破損しないようにする方法は?

コマンドオプションがコマンド内で実行されている他のスクリプトを破損しないようにする方法は?

実行中にmy_script.shscript() を実行する bash シェル script() があります。their_script私のスクリプト(my_script.sh)は次のようになります。

THISDIR=`dirname $(readlink -f $0)`
main() {
    cd $THISDIR
    source their-script
}
main "$@"

their-script変更しないでください。 their-scriptこれがあります:

BDIR="$1"
...
BDIR=`readlink -f "$BDIR"

上記のすべてがうまく機能します。いくつかのオプションを追加したいので、my_script.sh次のように変更しました。

THISDIR=`dirname $(readlink -f $0)`
check_options() {
    while [ "$1" != "" ]; do
        case $1 in
            --username )  shift
                          OPTIONS_USERNAME=$1
                          ;;
            * )           # No more options
                          ;;
        esac
        shift
    done
}

main() {
    check_options
    cd $THISDIR
    source their-script
}
main "$@"

これで実行すると、./my_script.sh --username example実行their-script中に失敗します。

readlink -f --username

そして次の行を吐きます。

readlink: unrecognized option '--username'

このようにして、スクリプトの位置パラメータが他のスクリプトを破損するのを防ぐにはどうすればよいですか?

ベストアンサー1

@roaimaが指摘したように、別のプロセスでスクリプトを実行したいかもしれません。内部の仕組みを完全に理解せずにコードに含めることは非常に危険です。

FILE_TO_REMOVE="/tmp/foobar"
source some-cool-script
rm -Rf "$FILE_TO_REMOVE"

明らかに、これは素晴らしいスクリプトに次のものが含まれる可能性があるため、正しい方法ではありません。

FILE_TO_REMOVE=/

スクリプトがいつでも変更される可能性があることは言うまでもありません(「積極的に」維持されていなくても)。

これに加えて、次の点も考慮する必要があります。

  1. 位置引数の処理は、残りの引数の数に応じてより適切に制御できます。

    while [ $# -gt 0 ]; then
    ...
    done
    

    ""区切り文字として使用したい場合を除き、空の文字列likeは完全に有効な引数になることができます。これを行っても(伝統的に--使用されている)上記の条件を維持し、以下を使用する方が良いかもしれません。

        case "$1" in
            ...
            "")
                shift
                break
                ;;
            ...
        esac
    

    これはメンテナンスが簡単です。

  2. この$@変数は範囲別に適用されます。つまり、通常のように外部スクリプトを実行することを決定した場合(たとえば、コードにインポートするのではなく呼び出すなど)、パラメータを渡す必要があります。

    their-script "$@"
    

    特に、スクリプトが昇格された権限で実行されている場合は、スクリプトへのフルパスを使用するのも悪くない考えです。

  3. 上記は、実際にはコマンドライン引数を確認しないという意味でもあります。

    main() {
        check_options
    }
    main "$@"
    

    電話してください。

        check_options "$@"
    
  4. ただし、上記は、パラメータがいかなるmain方法でも変更されないことを意味しますcheck_options。特定のオプションをフィルタリングして外部スクリプトが競合しないように(そして質問がある場合)、次の2つのオプションがあります。

    • オプション解決をmainスクリプトのグローバルスコープに配置します。コードの清潔さの観点から見ると、より速く、少し汚れています。

    • 別の関数でオプションの解析を維持し、いくつかの変数処理を実行します。

      check_options {
          # parse options magic
          # what needs to be passed over is
          # kept in a separate variable
          PASS_THROUGH_OPTS=...
      }
      
      main {
          check_options "$@"
          set -- $PASS_THROUGH_OPTS
          ...
      }
      

      これは、位置パラメータにスペースやその他の単語区切り文字が含まれる可能性を処理しないことに注意してください。配列(実装によって異なります)を使用することに加えて、これを正しく処理する他の方法はありません。

      check_options {
          ...
              # parameter should be kept for further use
              x=( "${x[@]}" "$1" )
          ...
      }
      
      check_options "$@"
      set -- "${x[@]}"
      

おすすめ記事