Command-Line

使用使用者指定的參數在子目錄中執行 cargo 命令

  • May 23, 2022

我有一個目錄結構,如:

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.

雙引號是必要的,以防止外殼與--. 使用者可以傳遞其他參數而無需--.

我試過find . -name 'Cargo.toml' -type f -print -exec cargo -v "$@" --manifest-path {} \;了,但得到錯誤“錯誤:沒有這樣的子命令:測試–忽略”。顯然,整個事情是作為字元串傳遞的,而不是作為單獨的字元串傳遞的。

這個怎麼做?

外殼不會弄亂--.

做就是了:

#! /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]辨識和剝離Comments,@在雙引號內保留空元素),也許只做一次標記化以避免每次在循環中都必須這樣做,甚至將它們儲存在$argv(aka $@)中,所以我們回到第一方:

#! /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與標準一起傳遞給您的腳本時,這又是一種過度殺傷力"$@"就像上面的第一個例子一樣。


現在,事實證明,您的問題是 是在子命令的選項分隔符--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.

引用自:https://unix.stackexchange.com/questions/703515