【问题标题】:How to escape a NULL byte as an argument to a shell command inside a Makefile如何将 NULL 字节作为参数转义到 Makefile 中的 shell 命令
【发布时间】:2013-06-10 21:50:55
【问题描述】:

在 Makefile 中,我运行一个 shell 命令,我想将一个 NULL 字节作为参数传递。以下尝试失败:

echo $(shell /bin/echo -n $$'\x00' | ruby -e "puts STDIN.read.inspect")

它生成:

echo "$\\x00"

相反,我期望:

echo "\u0000"

如何正确转义这样的 NULL 字节?

【问题讨论】:

    标签: shell null makefile escaping


    【解决方案1】:

    echo 默认禁用反斜杠转义的解释。您需要提供-e 选项才能启用它。

    $ echo -ne "\x00" | ruby -e "puts STDIN.read.inspect"
    "\u0000"
    

    【讨论】:

    • 我对通过管道传递空字节不感兴趣,而是直接在参数中传递它们。
    • 哦!所以你需要清楚地说明你打算做什么。各种答案试图解决您描述的问题。
    • 让我引用我的问题:>我想传递一个 NULL 字节作为 argument
    • 举了一个例子。
    • 如果您不喜欢写下被否决的答案,请随时删除您的答案:meta.stackexchange.com/questions/91124/…
    【解决方案2】:

    由于 execve(2) 语义,不可能将包含空字节的字符串作为参数传递。每个参数字符串都以空字节结尾,因此无法区分包含的空字节和字符串的结尾。

    【讨论】:

    • 否,尝试使用file --print0 | cut,现在改用file -F "/" | cut -d "/"
    • 使用cut -z/--zero-terminated
    【解决方案3】:

    echo 的这些用法是完全不可移植的。使用printf,除了最简单的字符串之外,它更易于使用,而且更便携。

    $ cat makefile
    all:
            printf '\0' > foo.out
            od -a foo.out
    
    $ make
    printf '\0' > foo.out
    od -a foo.out
    0000000 nul
    0000001
    

    【讨论】:

    • 如果您想要一个好的答案,请提出一个好问题。您的示例显示了回显 NUL 字节。我向您展示了如何生成 NUL 字节。如果这不是你想要的,那么问你想要回答的问题。如果您真的想知道如何将 find -print0 的输出拆分为 shell 中的各个参数,那么请提出这个问题。然后我们都可以立即解释说,这样的事情在 shell 脚本中分解单词的上下文中没有用。
    • 似乎我无法想出一个最小的例子来不让读者的想法偏离我的意图。你有足够的声誉来编辑我的问题。请向我展示一个完全符合我将 NULL 字节作为参数传递的问题意图的示例。
    • 无法提出一个好的例子是麻烦的第一个暗示。至少在更高的层次上描述你想要完成的事情。在其他地方,您提到将find -print0 的输出发送到cut... 但是然后呢? cut 的输出到哪里去了?无论它走到哪里,显然它不会再被 NUL 字节分隔,所以基本上-print0 是没用的。从根本上说,-print0 只有在输出的最终消费者可以自身拆分 NUL 字节时才有用:shell 无法做到这一点。在这里,我们不知道该消费者是什么,因此我们无法提供建议。
    • 我认为将问题限制在我遇到问题的具体细节上是件好事。也许下次我会问:“我正在努力实现世界和平。我写的1.000.000行代码可以在bla.bla.bla查看。请修复我的代码!!!”
    【解决方案4】:

    如果有其他人来这里寻找如何通过 ruby​​ 反引号中的 shell 命令转义空值:

    irb(main):024:0> `curl --silent http://some-website-or-stream.com | sed 's/\\x0//g' 1>&2`
    => ""
    

    【讨论】:

      【解决方案5】:

      你不能在 bash 中使用 NUL 作为参数

      您不能使用$'\0' 作为参数,将其存储为变量或使用命令替换$(printf '\0'),因为bash(以及大多数shell?)使用以null 结尾的C 字符串。 NUL 之前的前导字符串被解释为字符串,而尾随字符串被丢弃。

      您只能使用管道输入 - printf '\0' | cat -v 或让生成的程序使用文件进行输入。

      使用另一种输入方式

      大多数使用行字符串NUL 字符串(xargscut、...)输入的程序通常都有一个-z 标志。这主要用于处理路径,因为字符可能包含除NUL 之外的任何字符。

      findgit ls-files 这样的程序支持输出这种格式,通常以-print0-0 标志的形式。

      sedtrbash 等程序。人。使用 \0\x0\x00 等特殊转义字符生成 NUL 字节。

      按摩输入

      OP原本似乎想知道如何use cut with a NUL delimiter。问题通常是使用\n 分隔某些内容,其中\n 是值的有效部分,而不是行分隔符(通常在路径中)。

      假设您将文件分组,每个文件由NUL 字符分隔,组由\n 分隔。

      # Temporary mock output with NUL columns and newline rows
      printf 'foo\0bar\nbar\0\nFOO\0BAR\0\n' > /tmp/$$.output
      

      一种变通方法是通过组合sedawktr 来发挥创意,将输出调整为适合我们输入/命令的内容。

      我们的.sed

      #!/usr/bin/sed -nf
      
      # beginning
      :x 
      # match \0\n
      /\x0$/ {
       # Change \0\n to \n
       s|\x0$|\n|g
       # print
       p
       # delete
       d
      }
      # match \n with no leading \0
      /[^\x0]$/ {
       # change \0 to \1
       s|\x0|\x1|g
       # read next line
       N
       # branch to beginning
       bx
      }
      

      在这种情况下,我们映射:

      • \0\n => \n
      • \0 后面没有\n => \1
        虽然文件名中的字符是有效字符,但不太可能造成问题。
      # Change NUL to another unlikely to be used control character
      sed -f our.sed /tmp/$$.output |\
        cut -d $'\x1' -f 2
      

      输出

      bar
      BAR
      

      【讨论】:

        猜你喜欢
        • 2011-10-18
        • 1970-01-01
        • 2015-07-08
        • 2010-12-19
        • 2017-12-27
        • 1970-01-01
        • 2012-04-16
        • 2022-11-30
        • 1970-01-01
        相关资源
        最近更新 更多