Bash 带空格的Shell变量,引用单个命令行选项
Autoconf脚本在文件名或路径名中有空格问题。比如说,Bash 带空格的Shell变量,引用单个命令行选项,bash,shell,autoconf,Bash,Shell,Autoconf,Autoconf脚本在文件名或路径名中有空格问题。比如说, ./configure CPPFLAGS="-I\"/path with space\"" 结果显示在(config.log): 来自./configure的compile命令是ac_compile='$CC-c$CFLAGS$cppfagas conftest.$ac_ext>&5',我无法修改此命令(我可能可以,但以这种方式处理autoconf不是一个通用的解决方案) 我认为这可以归结为获取一个shell变量,该变量包含要解析为单
./configure CPPFLAGS="-I\"/path with space\""
结果显示在(config.log):
来自./configure的compile命令是ac_compile='$CC-c$CFLAGS$cppfagas conftest.$ac_ext>&5'
,我无法修改此命令(我可能可以,但以这种方式处理autoconf不是一个通用的解决方案)
我认为这可以归结为获取一个shell变量,该变量包含要解析为单个命令行变量的空格,而不是在空格处拆分的空格。我能想到的最简单的shell示例是创建一个带有空格的文件,并尝试使用ls
列出,其中shell变量作为ls
的参数:
$ touch "a b"
$ file="a b"
$ ls $file
ls: a: No such file or directory
ls: b: No such file or directory
这是可行的,但不合法,因为在autoconf中,我无法修改shell代码:
$ ls "$file"
a b
以下引用内容的尝试均无效:
$ file="\"a \"b"; ls $file
ls: "a: No such file or directory
ls: b": No such file or directory
$ file="a\ b"
$ file="a\\ b"
$ file="`echo \\"a b\\"`"
等等
这在shell脚本中是不可能实现的吗?是否有一个神奇的引号将带空格的shell变量扩展为单个命令行参数?您应该尝试设置
$IFS
环境变量
来自man bash(1):
IFS-用于分词的内部字段分隔符
展开后,使用read builtin将行拆分为单词
指挥部。默认值为“空间选项卡换行符”
比如说
IFS=<C-v C-m> # newline
file="a b"
touch $file
ls $file
IFS=#换行符
file=“a b”
触摸$file
ls$文件
不要忘记将
$IFS
设置回原位,否则会发生奇怪的事情。使用引号很有趣。通过(轻松地)阅读bash手册页,我认为您必须使用\来避开空格,因此“/path with space”变成了/path\with\space。我从未尝试过引用,但似乎它通常不起作用(您的ls示例)。转义可以在不引用和不更改IFS的情况下使用ls
如果使用命令的“转义空格”格式,会发生什么情况?如果发出命令
gcc -I"x y z"
在shell中,单个命令行参数“-Ix y z”肯定会传递给gcc。这是毫无疑问的。这就是双引号的全部含义:例如,双引号中的内容不受字段拆分的约束,因此也不受$IFS的约束
但是你需要注意你需要的报价数量。例如,如果你说
file="a b" # 1
然后你说
ls $file # 2
发生的情况是,文件变量的内容是“ab”,而不是“ab”,因为在解析第1行时双引号被“吃掉”。然后,替换的值以字段分隔,在两个文件“a”和“b”上得到ls。得到你想要的东西的正确方法是
file="a b"; ls "$file"
现在,原始情况下的问题是,当您将变量设置为包含双引号的字符串时,双引号随后不会被解释为shell引号符号,而是被解释为普通字母。这就是为什么当你做这样的事情时
file="\"a b\""; ls $file
实际上,在分析ls命令时,shell将文件变量的内容标记为“a”和“b”;双引号不再是shell引号字符,而只是变量内容的一部分。如果你设置
file="\$HOME"; ls $file
您得到一个错误,即“$HOME”目录不存在——没有进行环境变量查找
所以你最好的选择是
您希望以以下任一方式引用整个参数:
./configure "CPPFLAGS=-I/path with space"
./configure CPPFLAGS="-I/path with space"
然后,/configure
命令会看到一个参数
"CPPFLAGS=-I/path with space"
它被解析为一个名为
«CPPFLAGS»
的参数,其值为«-I/path with space»
(为清晰起见,添加了括号)。在Unix世界中使用目录名中的空格只是自找麻烦。这不仅仅是在shell脚本中引用的问题(无论如何都需要正确完成):有些工具根本无法处理文件名中的空格。例如,您不能(可移植地)从“foobar/baz.c
”编写一个Makefile
规则,该规则显示build“baz.o
”
如果出现上述CPPFLAGS
,我会按照优先顺序:
/configure CC=mygcc
。在这种情况下,mygcc
可能是
!/bin/sh
gcc "-I/foo bar/include" "$@" !/垃圾箱/垃圾箱 gcc“-I/foo-bar/包括“$@”/tmp/mypath
),并使用CPPFLAGS=-I/tmp/mypath
一切都取决于变量的使用方式。首先,请注意,如果您使用的是Autoconf,这可能意味着最终将使用
make
,因此规则由make
指定,尤其是默认的make
规则。尽管您可能希望只使用自己的规则,但工具之间的内容必须保持一致,并且一些变量具有标准含义,因此您不希望偏离它们。这不是CPPFLAGS
的情况,但这应该与标准的CFLAGS
类似。请参阅,其中变量仅通过标准sh
分词进行扩展,而不提供任何引用机制(字段分隔符由$IFS
控制,但不要更改IFS
变量以接受空格作为普通字符,因为这会破坏其他功能,例如能够以标准方式在此类变量中提供多个-I
和/或-L
选项)
由于make
有这样的限制,我认为在Autoconf中避免这种限制是没有用的
现在,由于空格必须是字段分隔符,唯一的可能是提供不带空格字符的路径名。如果将来支持路径名中的空格,这可能通过路径名编码完成,并在高级UI上解码(有点像URL)
!/bin/sh
gcc "-I/foo bar/include" "$@"$ file="\"a b\""
$ eval ls $file