使用使用者指定的參數在子目錄中執行 cargo 命令
我有一個目錄結構,如:
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 使用
z
orZ[options]
和Q
參數擴展標誌對那個參數進行 shell 標記化和引號刪除,使用"${(Q@)${(Z[n])1}}"
(Z[n]
對於n
ewline 也被接受為分隔符,另請參見z[Cn]
辨識和剝離C
omments,@
在雙引號內保留空元素),也許只做一次標記化以避免每次在循環中都必須這樣做,甚至將它們儲存在$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
.