在保留空格的同時替換命令行參數
我想有選擇地替換正在傳遞的命令行參數,以便為正在執行的下游 cmd 自動格式化它。論點將有空格,這就是爭論的焦點。
我目前正在這樣做:
set -- $(echo $* | sed -e "s/$_ARG/--description=\"$_ID - $_SUMMARY\"/")
新的論點,
--description="$_ID - $_SUMMARY"
被分裂了。我執行下游 cmd:
<cmd> "$@"
編輯:
我可能有任意數量的參數,但一個範例案例是:
從
activity --description='handle null'
至:
activity --description='$SOME_VARIABLE - handle null'
最終,當我使用“$@”執行下游命令時,它已經在那里拆分了,所以它不能按我的意願工作。它最終像
activity --description=value - handle null
--description=value
,-
,handle
, 和null
then 被認為是單獨的參數。
您的程式碼中有一些問題。其中之一是使用不帶
$*
引號的,這將導致 shell 將原始參數拆分為任何字元$IFS
(預設情況下是空格、製表符、換行符)上的單詞,並對生成的單詞應用文件名萬用字元。如果您想要支持包含空格、製表符或換行符的多個參數,引用$*
as"$*"
也不是您想要的,因為這將是一個字元串。切換到 using"$@"
將無濟於事,因為echo
只會產生一個 each 參數,其間有空格以供sed
閱讀。
echo
可以對任何包含反斜杠序列的字元串進行特殊處理,例如\n
and\t
,具體取決於 shell 及其目前設置。在某些 shell 中,echo -n
可能不會輸出-n
(可能還有其他有問題的字元串,例如-e
)。如果您願意將
sed
其視為文本(參數可能是多行字元串),則用於修改參數可能會在單個參數上起作用,但在這種情況下,您正在一次對所有參數應用一些編輯腳本,這可能失火。但是,拆分結果字元串的是不引用與 . 一起使用的命令替換
set
。這將重新拆分結果sed
並再次對結果應用文件名萬用字元。您將需要解析您打算修改的命令行選項。簡而言之,循環遍歷參數,並修改您要修改的參數。
以下腳本在long 選項的每個實例的選項參數的開頭
sh
添加字元串。如果 long 選項後面緊跟一個空格,如,則在將其修改為 final 之前,將用 a 重寫,就好像腳本已用 呼叫一樣。hello -
--description``--description "my thing"``=``--description="my thing"``--description="hello - my thing"
#!/bin/sh SOME_VARIABLE=hello skip=false for arg do if "$skip"; then skip=false continue fi # Re-write separate option-argument with "=". # This consumes an extra argument, so need to skip # next iteration of the loop. case $arg in --description) arg=--description=$2 shift skip=true esac # Add the value "$SOME_VARIABLE - " to the start of the # option-argument of the --description long option. case $arg in --description=*) arg=--description="$SOME_VARIABLE - ${arg#--description=}" esac # Put the (possibly modified) argument back at the end # of the list of arguments and shift off the first item. set -- "$@" "$arg" shift done # Print out the list of arguments as strings within "<...>": printf '<%s>\n' "$@"
${arg#--description=}``--description=
從 的值中刪除前綴字元串$arg
,保留原始選項參數字元串。範例執行:
$ sh ./script -a -b --description="my thing" -c -d --description "your thing" -e <-a> <-b> <--description=hello - my thing> <-c> <-d> <--description=hello - your thing> <-e>
如果您總是期望有 long 選項及其由
=
字元分隔的選項參數,則程式碼可能會大大簡化:#!/bin/sh SOME_VARIABLE=hello for arg do # Add the value "$SOME_VARIABLE - " to the start of the # option-argument of the --description long option. case $arg in --description=*) arg=--description="$SOME_VARIABLE - ${arg#--description=}" esac # Put the (possibly modified) argument back at the end # of the list of arguments and shift off the first item. set -- "$@" "$arg" shift done printf '<%s>\n' "$@"
使用與上述相同的參數進行測試執行(
--description
不會修改第二個實例,因為它與模式不匹配--description=*
):$ sh ./script -a -b --description="my thing" -c -d --description "your thing" -e <-a> <-b> <--description=hello - my thing> <-c> <-d> <--description> <your thing> <-e>
上面較短的第二個腳本的
bash
變體,使用 shell 模式匹配[[ ... ]]
代替case ... esac
,並在循環過程中使用數組來保存可能修改的參數:#!/bin/bash SOME_VARIABLE=hello args=() for arg do if [[ $arg == --description=* ]]; then arg=--description="$SOME_VARIABLE - ${arg#--description=}" fi args+=( "$arg" ) done set -- "${args[@]}" printf '<%s>\n' "$@"
在 ksh93、zsh 或 bash 中,您可以執行以下操作:
set -- "${@/#--description=*/--description=$NEW_DESCRIPTION}"
用with替換起始位置參數(
#
在開始處錨定模式)。--description=``--description=<contents-of-NEW_DESCRIPTION-variable
,
ksh93
可以縮短為:set -- "${@/#@(--description=)*/\1$NEW_DESCRIPTION}"
等價於
zsh -o extendedglob
:set -- "${@/#(#b)(--description=)*/$match[1]$NEW_DESCRIPTION}"
但也許你也可以這樣做:
set -- "$@" "--description=$NEW_DESCRIPTION"
大多數實用程序都接受多次採用相同的選項,並且這是最後一次優先發生¹。例如:
$ echo x | grep -H --label=foo --label=bar . bar:x
在
zsh
中,您可以執行以下操作:argv[(i)--description=*]=--description=$NEW_DESCRIPTION
替換以 開頭的第一個參數
--description=
,--description=<contents-of-NEW_DESCRIPTION-variable
或者如果沒有找到,則將其作為新參數添加到末尾。或者:
argv[(I)--description=*]=--description=$NEW_DESCRIPTION
相同,除了它是最後一個被替換的匹配項,如果找不到,它會在開頭插入。
也可以用多個參數替換一個參數:
argv[(i)--description=]=(--description=$NEW_DESCRIPTION --other-args)
或者用
--description
以下參數替換一個參數--description=$NEW_DESCRIPTION
:argv[n=argv[(i)--description],n+1]=--description=$NEW_DESCRIPTION
--description
(再次,在元素中未找到if 的末尾添加)。要刪除以開頭並在末尾添加一個的所有參數:
--description=
set -- "${@:#--description=*}" --description=$NEW_DESCRIPTION
在
bash
4.4+ 中,對參數進行一些轉換的另一個選擇是訴諸perl
,將位置參數作為參數傳遞並將它們作為 NUL 分隔列表讀回(因為bash
變數無論如何都不能包含 NUL):readarray -td '' newargs < <( SEARCH="$_ARG" REPLACE='--description=something' perl -l0e ' for (@ARGV) { s/\Q$ENV{SEARCH}\E/$ENV{REPLACE}/; print; }' -- "$@" ) set -- "${newargs[@]}"
比
sed
你必須為 SEARCH 和 REPLACE 進行一些轉義更合適。¹ 除了那些
--quiet --quiet
比--quiet
某些實用程序更安靜的累積值,或者-o pid -o ppid
指定ps
多個輸出欄位的 。在某些情況下,順序很重要。例如,更改--description=foo --no-description
為--description=bar --no-description
可能與更改為 不同--description=foo --no-description --description=bar
。