web-dev-qa-db-ja.com

cdのラッパーを作成するときに、cd "$ 1"ではなくcd "$ @"を使用する必要があるのはなぜですか。

他のところで私は以下のようにcd関数を見ました:

cd()
{
 builtin cd "$@"
}

なぜ$@ の代わりに $1

私はテストディレクトリ「r st」を作成し、この関数を含むスクリプトを呼び出しました。

$ . cdtest.sh "r st"

だが $ . cdtest.sh r stを使用したかどうかに失敗しました"$@"または"$1"

25
RKA

なぜなら、bash(1)によれば、cdは引数を取ります。

   cd [-L|[-P [-e]] [-@]] [dir]
          Change  the  current  directory to dir.  if dir is not supplied,
          ...

したがって、ディレクトリは実際には$1にない可能性があります。代わりに、-Lや別のフラグなどのオプションが存在する可能性があるためです。

これはどれくらい悪いですか?

$ cd -L /var/tmp
$ pwd
/var/tmp
$ cd() { builtin cd "$1"; }
$ cd -L /var/tmp
$ pwd
/home/jhqdoe
$ 

cd "$1"…の使用が期待した場所に到達しないと、事態は非常に悪化する可能性があります。

57
thrig

"$@"を使用すると、すべての引数がcdに渡され、$1は最初の引数のみを渡します。

あなたの例では

$ . cdtest.sh "r st"

常に1つの引数を渡すだけで機能しますが、次のようなフラグも渡す場合

$ . cdtest.sh -L "r st"

次に、"$@"のみが正しく実行され、"$1"cd -Lに展開され、ディレクトリが完全に失われます。

しかしながら

$ . cdtest.sh r st

2つのパラメーターrstをcdに渡すと、どちらの場合も失敗します。これは、cdを実行する有効な方法ではありません。パラメータはスペースで区切られ、最初の例のように引用符で囲むか、エスケープ(r\ st)して、1つの引数として扱う必要があります。

ただし、cdの場合、フラグを渡すことは非常にまれであり、複数のディレクトリを渡すことはできないため、cdに対する"$1"または"$@"の実際の使用では違いがわかりません。しかし、他のコマンドについてはwill違いに気づくので、このようなラッパー関数またはスクリプトを作成する場合は常に"$@"を使用することがベストプラクティスです。

19
Michael Daffin

no引数がある場合もあります:

$ cd /tmp; cd; pwd
/home/muru
$ cd_func() { builtin cd "$1"; }
$ cd_func /tmp; cd_func; pwd
/tmp

cdは引数なしでホームディレクトリに変更されます。引数なし、"$@"は何にも展開されませんが、"$1"は空の文字列に展開されます。これらは異なります:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||
14
muru

Bashスクリプトへの引数はスペースで区切られています。 $ 1が最初の引数です。あなたの例では...

例1では、$ 1は文字列「r st」です... 2番目の例では、$ 1は1文字の文字列 'r' ...です。

$ @はすべての引数です。

4
RubberStamp