ディレクトリ名にスペースが含まれていると、bash変数を使用してディレクトリに移動できない


11

次のコマンドを変数に保存したいとしましょう

cd "/cygdrive/c/Program Files/"

だから私はこれをする

dir="cd \"/cygdrive/c/Program Files/\""

Program Filesディレクトリに移動するコマンドを保存する必要があるため、$ dirと入力すると、そのディレクトリに移動します。引用が適切にエスケープされていることを確認するには、次のように入力します

echo $dir

それは私に与えます

cd "/cygdrive/c/Program Files/"

したがって、すべて正常に動作するはずです。ただし、入力すると、

$dir

私は得る

bash: cd: "/cygdrive/c/Program: No such file or directory

私は何を間違えていますか?私はCygwinを使用していますが、この問題はbash全般に当てはまると思います。


ディレクトリ名を囲む引用符を削除して、代わりに円記号でスペースをエスケープしてください。
マイクフィッツパトリック

回答:


8

簡単な答え:BashFAQ#050(「コマンドを変数に入れようとしていますが、複雑なケースは常に失敗します!」)を参照してください。

長い答え:bashはコマンドを解析するとき、変数を置き換える前に引用符を解析します。戻ることはなく、変数の値の引用符を再解析するため、有用なことは何もしません。コマンド解析したにコマンドを表示するため、エコーを使用してコマンドをチェックすることは完全に誤解を招きます。実際に実行されているものを確認する場合set -xは、実行時にシェルコマンドを出力するかprintf "%q " $dir; echo、単純なエコーの代わりに使用します。

複雑なコマンド(つまり、「単語」にスペースまたは他の特殊文字が含まれるコマンド)を保存する場合は、単純なテキスト変数ではなく配列に入れて、イディオム「 "$ { array [@]}」、次のように:

dir=(cd "/cygdrive/c/Program Files/")
"${dir[@]}"

さて、目的がタイプしやすい速記を作ることであるなら、これは明らかに進むべき道ではありません。代わりにシェルエイリアスまたは関数を使用します。

alias dir='cd "/cygdrive/c/Program Files/"'
dir

または

dir() { cd "/cygdrive/c/Program Files/"; }
dir

7

bashが展開されると$dir、単語の分割とグロブのみが実行されます。単語分割により、3つの単語が生成されます:cd"/cygdrive/c/ProgramおよびFiles/"。次に、実行するコマンドにはcd2つの引数があります。既存のディレクトリではないcd最初の引数のみを調べ"/cygdrive/c/Programます。

変数の内容に対して完全なシェル評価を実行する場合は、次を使用しますeval

eval "$dir"

周り$dirに二重引用符が必要であることに注意してください。そうでない場合、最初に単語分割が実行され、次にeval引数がスペースで連結されます。これはたまたまここで機能しますが、一般的には悪くなります(たとえば、ファイル名に2つの連続したスペースがある場合)。

ただし、文字列は、実行するシェルコマンドを保存する正しい方法ではありません。異常な要件がない限り、代わりに関数を使用する必要があります。

dir () {
  cd "/cygdrive/c/Program Files/"
}

あなたが本当にタイピングに興味を持っている場合は$dir、特定のディレクトリにスイッチすると、これはbashの4以来、単純な例ではない、入れてshopt -s autocdお使いに.bashrcセット

dir="/cygdrive/c/Program Files/"

その後、単に入力する"/cygdrive/c/Program Files/""$dir"、シェルプロンプトでそのディレクトリに切り替えることができます。あなたはまだ二重引用符が必要$dirです; 気に入らない場合は、bashの代わりにzshを使用してください。


6

コマンドを変数に保存することは、一般的にはお勧めできません。それが関数とエイリアスの目的です。

のではなく

dir="cd \"/cygdrive/c/Program Files/\""

次のいずれかを試してください。

dir="/cygdrive/c/Program Files"
...
cd "$dir"

または

dir() { cd "/cygdrive/c/Program Files"; }
dir

または

alias dir='cd "/tmp/Program Files"'
...
dir

最初のフォームは、ディレクトリ名を変数に保存するため、もう少し入力することを意味しますが、コマンドを実行すると、より明確になりますcd。2番目は、達成しようとしているものに最も近いものです。(bashではエイリアスをあまり使用しません。実際、エイリアスが機能よりも優れている点はわかりません。)

編集:

またdir、おそらくエイリアスまたは関数には悪い名前です。その名前の既存のコマンドがあるからです(ls少なくともGNU coreutilsを持っている場合は、基本的にはのバージョンです)。


賛成Storing commands in variables is generally not a good idea. That's what functions and aliases are for.
ロブ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.