Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 带空格的Shell变量,引用单个命令行选项_Bash_Shell_Autoconf - Fatal编程技术网

Bash 带空格的Shell变量,引用单个命令行选项

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变量,该变量包含要解析为单

Autoconf脚本在文件名或路径名中有空格问题。比如说,

./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