Bash

傳遞包含空格和萬用字元的參數的問題

  • December 17, 2014

如果參數可能包含萬用字元和/或空格,如果這些參數是可選的,那麼我在傳遞參數時會遇到問題。由於這聽起來很抽象,讓我們舉一個小例子:下面的 shell 腳本some_command.sh需要 2 或 3 個參數。第一個參數應該是命令行開關,第二個參數是可選的,如果存在,必須是形式的命令行開關,--NAME=VALUE最後一個參數是必需的,可以是任何東西:

#!/bin/bash
# This is file some_command.sh
# Synopsis:
# some_command.sh --switch1=val1 [--switch2=val2] arg
echo "switch1: $1"
shift
if [[ "$1" == --*=* ]]
then
 echo "switch2 ($1) detected"
 shift
fi
echo argument is ${1:?argument missing}

假設我通過以下方式some_command.sh從其他腳本呼叫caller.sh

#!/bin/bash
# This is file caller.sh
if [[ ${1:-x} == x ]]
then
 switch="--abc=long argument"
else
 switch=""
fi
some_command.sh "--exclude=*~" "$switch" arg

注意引用。引號--exclude是必須的,因為萬用字元表達式不能被shell擴展,而引號"$switch"是必須的,因為$switch可能包含帶有空格的文本,並且參數不能在空格上被打斷。

目的是如果我們執行caller.sh x,這應該導致

some_command.sh "--exclude=*~" "--abc=long argument"  arg

如果我們執行,比如說caller.sh y,這應該變成

some_command.sh "--exclude=*~" arg

caller.sh我在這裡提供的,不能正常工作,因為在後一種情況下,它會執行

some_command.sh "--exclude*~" "" arg

這是不正確的。

我試圖在命令前加上eval. 雖然這可以解決 的問題$switch,但它也會刪除 周圍的引號"--exclude",並且萬用字元將由 shell 評估。

我想我可以繼續使用eval, 並且只使用額外級別的引用,即"\"--exclude*~\"",但這是一個糟糕的解決方案。我想知道是否有人有更清潔的方法來做到這一點。

如果您想知道我為什麼會提出這個問題:我在編寫呼叫的腳本時偶然發現了這個問題zip,因為這些腳本應該能夠處理文件名中的空格。

順便說一句,如前所述,問題發生在bashand zsh。我也對聰明的解決方案感興趣,這些解決方案只適用於其中一個 shell。

使用數組,因為它可以擴展為可變數量的參數:

#!/bin/bash
# This is file caller.bash
switch=()
if [[ ${1-x} == x ]]
then
 switch=("--abc=long argument")
fi
some_command.sh "--exclude=*~" "${switch[@]}" arg

或者您可以使用以下${var+...}語法:

#!/bin/sh
# This is file caller.sh
unset switch
if [ "${1-x}" = x ]
then
 switch="--abc=long argument"
fi
some_command.sh "--exclude=*~" ${switch+"$switch"} arg

請注意,使用 zsh,您可以執行以下操作:

#!/bin/zsh
switch=
if [ "${1-x}" = x ]
then
 switch="--abc=long argument"
fi
some_command.sh "--exclude=*~" $switch arg

zsh不會在參數擴展時執行split+glob,但它會執行空刪除,這正是您想要的。

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