我试图在解析选项时接受以空格分隔的字符串代替$ OPTARG
例如
./script -k '1 2 ad'ias'
如图所示,第三个字符串可以包含任何特殊字符。我想解析整个字符串并处理一些选项时,是否有一种方法可以忽略两者之间的引号
试图插入\字符,但由于我无法在字符串中插入任何字符,因此不适用于我的情况。
while getopts "a:k:" option
do
echo "${option}"
case ${option} in
a)
function_a ${OPTARG} # <-- no quotes
;;
k)
function_k "${OPTARG}" # <-- quotes
;;
esac
done
答案 0 :(得分:2)
我不确定我是否完全理解困难所在;处理带有特殊字符的字符串有点棘手,但是(除了NUL字符之外)基本上是可行的。要注意的主要事情是:
在表示字符串文字时(在脚本中,或将参数传递给脚本时),必须使用该字符串的有效外壳表示形式,而不仅仅是原始字符串。例如,假设您要传递/使用以下字符串:
12 34 kla#42@!' 2 M$" rtqas;::#
有多种方式表示 该字符串以用于Shell脚本或命令行。您可以不加引号,但是转义各个特殊字符,例如:
12\ 34\ kla\#42@\!\'\ 2\ M\$\"\ rtqas\;::\#
或者您可以将其用双引号引起来,并转义那些在双引号内保留特殊含义的字符(即双引号,反引号和美元符号,如果它是bash交互式shell感叹号) :
"12 34 kla#42@!' 2 M\$\" rtqas;::#" # For a non-interactive shell
"12 34 kla#42@\!' 2 M\$\" rtqas;::#" # For an interactive shell
如果不包含单引号,则可以将其单引号。既然如此,您将无法使用该方法。但是您可以混合使用多种方法,例如在不包含单引号的部分周围使用单引号,并对单引号进行转义或双引号:
'12 34 kla#42@!'\'' 2 M$" rtqas;::#' # Single-quote is escaped
'12 34 kla#42@!'"'"' 2 M$" rtqas;::#' # Single-quote is double-quoted
在bash(但没有其他一些shell)中,还有用$' ... '
编写的ANSI-C转义字符串:
$'12 34 kla#42@!\' 2 M$" rtqas;::#' # Single-quote is the only character that needs escaping
请注意,以上所有都是表示完全相同的字符串的不同方式;一旦外壳解析了它,它们中的任何一个都会得到相同的结果。您可以使用任何方便的方法,但是必须使用字符串的语法有效表示形式。
一旦字符串存储在参数/变量中,则必须在对该变量的引用两边加上双引号。在大多数Shell上下文中,当使用不带引号的变量时,Shell会将其拆分为多个单词(基于空格或IFS
中的任何内容),并尝试扩展任何类似于文件通配符的内容;你不要这个但是,如果用双引号引起来,则变量将被扩展,并且不做进一步的解析,它将直接进行无干扰的传递。
实际上,即使您不希望变量引用包含特殊字符,也应该几乎总是在shell脚本中双引号。我们在这里看到很多shell问题,这些问题的答案是“如果将变量引用双引号,就不会有这个问题” ...
这是一个基于您的脚本的示例:
#!/bin/bash
printopt() {
printf '%s value is: <<%s>>\n' "$1" "$2" # Double-quotes required here
}
while getopts "a:k:" option
do
case "${option}" in # This is one of the few places it's safe to leave off double-quotes. But they don't hurt.
a)
printopt "-a" "${OPTARG}" # Double-quotes required here
;;
k)
printopt "-k" "${OPTARG}" # Double-quotes required here
;;
esac
done
并使用各种字符串表示形式运行它:
$ ./argtest.sh -a 12\ 34\ kla\#42@\!\'\ 2\ M\$\"\ rtqas\;::\# -k "1 2 ad'ias"
-a value is: <<12 34 kla#42@!' 2 M$" rtqas;::#>>
-k value is: <<1 2 ad'ias>>
$ ./argtest.sh -a '12 34 kla#42@!'"'"' 2 M$" rtqas;::#' -k $'1 2 ad\'ias'
-a value is: <<12 34 kla#42@!' 2 M$" rtqas;::#>>
-k value is: <<1 2 ad'ias>>
好的,好的,在某些情况下,它比这更复杂:
在某些情况下,字符串将在外壳解析过程中多次运行,例如在ssh
上运行时(命令由本地外壳处理,并传递给远程计算机,然后由 that 外壳处理并执行),或用作外壳alias
(alias
命令将被解析,存储结果,然后在使用时再次解析) 。在这些情况下,您实际上需要两个(或可能更多)层进行引号/转义:取原始字符串,通过上述任何一种方法引号/转义,然后取那个 >字符串并用引号/转义 (可能是通过其他方法)。
某些版本的echo
将解析字符串中的转义(反斜杠)序列(使用与Shell本身不同的规则),这可能导致混淆。我建议您在可能会出现问题的情况下改用printf
;唯一的问题是它比echo
更复杂:它不仅打印其参数,它使用的第一个参数是一个格式字符串,用于控制其余参数的打印方式。请参阅上面脚本中的示例。
如果将字符串传递给另一个脚本,该脚本在其参数和变量引用周围不使用双引号,那么您就注定了。在这种情况下,唯一可以做的就是修复其他脚本。