web-dev-qa-db-ja.com

引数としてスペースを使用してパスを渡す

スペースを含むいくつかの文字列変数を引数としてプログラムに渡すのに問題があります。
渡された引数をデバッグして表示するために、デモを作成しましたPythonスクリプト-:

##### show_args.py #####

import sys

def main():
    # Display the arguments passed to the script
    print "Number of arguments =", len(sys.argv)
    for arg in sys.argv:
        print arg

if __name__ == '__main__':
    main()

さて、問題を示すスクリプト-:

path_with_spaces="$HOME/blah blah"
arg_list="$path_with_spaces/abc $path_with_spaces/xyz"

python show_args.py $arg_list

出力-:

Number of arguments = 5
show_args.py
/home/anmol/blah
blah/abc
/home/anmol/blah
blah/xyz

私が実際に欲しいのはこれです-:

path_with_spaces="$HOME/blah blah"

python show_args.py "$path_with_spaces/abc" "$path_with_spaces/xyz"

出力-:

Number of arguments = 3
show_args.py
/home/anmol/blah blah/abc
/home/anmol/blah blah/xyz

問題がスペースを含むパスでのみ発生していることを確認するために、次のスクリプトを作成しました-:

path_without_spaces="$HOME/blah"
arg_list="$path_without_spaces/abc $path_without_spaces/xyz"

python show_args.py $arg_list

出力-:

Number of arguments = 3
show_args.py
/home/anmol/blah/abc
/home/anmol/blah/xyz

この問題の解決策を探しているときに、 この回答 に遭遇しました。これによると、正しい方法は、引数を文字列変数ではなく配列変数に入れることです。
この新しいアプローチを示すスクリプト-:

path_with_spaces="$HOME/blah blah"
arg_list=("$path_with_spaces/abc" "$path_with_spaces/xyz")

python show_args.py "${arg_list[@]}"

出力-:

Number of arguments = 3
show_args.py
/home/anmol/blah blah/abc
/home/anmol/blah blah/xyz

このソリューションは正しく機能していますが、配列変数ではなく文字列変数を使用して同じことを実現できる方法があるかどうかを知りたいです。

私のシステム構成-:

  • Ubuntu 14.04 LTS
  • Bash 4.3.11
  • Gnomeターミナル3.6.2
3

に:

path_with_spaces="$HOME/blah blah"
arg_list="$path_with_spaces/abc $path_with_spaces/xyz"

python show_args.py $arg_list

スカラー/文字列変数を使用し、split + glob演算子(その変数を引用符で囲まないまま)を使用して、その変数のコンテンツを分割し、pythonに渡す引数を生成しています。

splitsplit + glob演算子の一部は、$IFS特殊パラメータに格納されている文字を分割します。

ここでは、glob部分を無効にして、パスに見つからない文字で分割することができます。たとえば、newlineがパスに見つからない場合:

path_with_spaces="$HOME/blah blah"
arg_list="$path_with_spaces/abc
$path_with_spaces/xyz"
IFS="
"
set -f # disable glob.
python show_args.py $arg_list

シェルの引用を使用し、evalを使用して、シェルにそれらの引用を解釈させることもできます(ここではbash固有の機能を使用)。

printf -v arg_list '%q ' "$path_with_spaces/abc" \
                         "$path_with_spaces/xyz"

eval "python show_args.py $arg_list"
4

はい。

デフォルトのパスセパレータを使用して、パスを区切ることができます。パス名に不正な文字は2種類あります。

  • \0NUL文字

  • /パスセパレータ

たまたま、シェルのInternal Field Separator$IFS特殊パラメーターを使用して、セパレーターのパス名を区切ることができます。 2つ以上の区切り文字が順番に発生する場合、結果のコンポーネントは\0NUL値の引数になります。これは、パス名にすることはできません。

動作するには、すべてのパスを直接ルート化する必要があります(したがって、ルート//を除外し、正規のパスがあることを確認する必要があります-または少なくともすべての//*(ドットは傷つかない-または助けになる)ごとに1回に絞り込まれます。あなたがそうしたら:


paths='/path/one//path/t w o//p a t h/t h r e e/'
set -f --; IFS=/
for p in ${paths#/}$IFS
do  printf ${p:+/}%s\\n "$*"
    set -- ${p:+"$@"/$p}
done

/path/one
/path/t w o
/p a t h/t h r e e

$PWD w/cdで正規パスを取得できます。


cd -- /some//../screwy/../path/to///destination
printf %s\\n "$PWD"

/path/to/destination

-Pスイッチを使用する場合cdは、現在の作業ディレクトリへの絶対的な物理パスが$PWDに設定されるようにします。それ以外の場合、-Lまたはデフォルトでcdを使用すると、シェルセッションの進行中に、シンボリックリンクされたディレクトリへの以前の変更によって暗示されるすべての間接化が維持されます。

そのため、ツリーを歩くことで、ツリー内の名前を最も確実に収集できます。

1
mikeserv