使用用户指定的参数在子目录中运行货物命令

使用用户指定的参数在子目录中运行货物命令

我的目录结构如下:

rust/
├── dir1/
│   └── Cargo.toml
└── dir2/
    └── Cargo.toml

我想创建一个将从该rust目录运行的 zsh 脚本,并且对于每个带有Cargo.toml文件的子目录,cargo使用用户指定的参数运行命令。

例子:

run.sh "test -- --ignored"应该运行cargo -v test -- --ignored --manifest-path ./dir1/Cargo.toml并且cargo -v test -- --ignored --manifest-path ./dir2/Cargo.toml.

双引号对于防止 shell 弄乱--.用户可以传递其他参数而不带--.

我已经尝试过find . -name 'Cargo.toml' -type f -print -exec cargo -v "$@" --manifest-path {} \;,但收到错误“错误:没有这样的子命令:测试 -- --ignored”。显然,整个内容作为字符串传递,而不是作为单独的字符串传递。

这个怎么做?

答案1

外壳没有搞乱--

做就是了:

#! /bin/zsh -
for toml (**/Cargo.toml(N.)) cargo -v "$@" --manifest-path $toml

并将其称为:

that-script test -- --ignored

使用 zsh globbing 相比有几个优点find

  • 隐藏的文件和目录将被忽略(D如果不需要,请添加限定符)
  • 列表已排序
  • 可以将包含的参数{}传递给cargo.

如果您想将一个参数传递给脚本,并且 shell 将其拆分为空格字符,并将生成的单词作为单独的参数传递给cargo,您可以这样做:

#! /bin/zsh -
for toml (**/Cargo.toml(N.)) cargo -v ${(s[ ])1} --manifest-path $toml

或者按字符(默认为空格、制表符换行符和 nul)$1进行分割:$IFS$=1

然后,你可以调用:

that-script 'test -- --ignored'

但这意味着用户无法将包含空格(或 IFS 字符)的参数传递给cargo.

或者,您可以告诉 shell 使用zorZ[options]Q参数扩展标志对该一个参数进行 shell 标记化和引号删除,使用"${(Q@)${(Z[n])1}}"(Z[n]对于newline 也被接受为分隔符,另请参阅z[Cn]识别和删除C注释,@在双引号内保留空元素),也许只进行一次标记化,以避免每次在循环中都这样做,甚至将它们存储在$argv(又名$@)中,所以我们回到了第一个:

#! /bin/zsh -
argv=( "${(Q@)${(Z[n])1}}" )
for toml (**/Cargo.toml(N.)) cargo -v "$@" --manifest-path $toml

然后能够做到:

that-script "test -- --opt1='foo bar' --opt2=$'blah\nblah' --opt3 ''"

例如, and test----opt1=foo bar--opt2=blah<newline>blah--opt3空字符串作为单独的参数传递给cargo

但同样,当您可以让用户将所有参数单独传递给您的脚本时(语法为他们的shell / 语言,而上面的Z/Q标志需要引用语法)以及将它们与标准zsh一起传递的脚本,如上面的第一个示例中所示。cargo"$@"


现在,事实证明,您的问题是 was 位于子命令的选项分隔--manifest-path path/to/Cargo.toml符之前。您始终可以将这些参数插入用户传递的参数列表中,如下所示:--test

#! /bin/zsh -
for toml (**/Cargo.toml(N.)) (
  argv[2,0]=(--manifest-path $toml)
  cargo -v "$@"
)

这样,当用户调用 时that-script test -- --ignored,脚本最终会调用cargo -v test --manifest-path path/to/Cargo.toml -- --ignored

相关内容