スペースを含むいくつかの文字列変数を引数としてプログラムに渡すのに問題があります。
渡された引数をデバッグして表示するために、デモを作成しました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
このソリューションは正しく機能していますが、配列変数ではなく文字列変数を使用して同じことを実現できる方法があるかどうかを知りたいです。
私のシステム構成-:
に:
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"
はい。
デフォルトのパスセパレータを使用して、パスを区切ることができます。パス名に不正な文字は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
を使用すると、シェルセッションの進行中に、シンボリックリンクされたディレクトリへの以前の変更によって暗示されるすべての間接化が維持されます。
そのため、ツリーを歩くことで、ツリー内の名前を最も確実に収集できます。