首页 > 解决方案 > 这个带有 printf -- "$(cat | sed...)" 的管道是如何工作的?

问题描述

第一个片段中发生了printf --什么?如何printf解析这样的命令以及最终的调用堆栈是什么样的?

$ printf '%x' 65537 | \
    printf -- \
    "$(cat | sed -E -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')" \
    | openssl base64 -e
AQAB
$ printf '%x' 65537 | \
    cat | sed -E -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g' \
    | openssl base64 -e
XHgwMVx4MDBceDAxCg==

标签: shellprintf

解决方案


我认为您可能误读了您要询问的脚本。

在第一个示例中,printf命令很简单:

printf '%x' 65537

这会将数字打印65537为十六进制值 ( 10001)。然后,该脚本使用 shell 管道符号 ( |) 将该命令的输出传递printf给第二个printf命令:

printf -- "$(cat | sed -E -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')"

在此命令中,--简单的意思是“在此之后没有 cli 选项”,用于确保之后--看起来像选项的任何内容都不会被视为选项。该命令的其余部分是一个 shell$(...)表达式,它将被包含在括号内的命令的输出替换:

cat | sed -E -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')

它从对 cat 的无用使用开始,它只是将标准输入(...这是上一个printf命令的输出...)传递给 stdoutput。以下sed命令包含两个表达式。第一个...

s/^(.(.{2})*)$/0\1/

...匹配任何包含奇数位数的行并在前面加上 a 0,确保每一行都有偶数位数。第二个表达...

s/(.{2})/\\x\1/g

将每两个字符 ( nn)替换为\xnn,这是一个printf格式代码,要求printf打印具有给定 ASCII 值的字符。

然后将第二个命令的输出通过printf管道传输到openssl base64 -e中,它会根据stdout接收到的任何内容生成 base64 编码stdin


所以当你运行时:

printf '%x' 65537 | \
    printf -- \
    "$(cat | sed -E -e 's/^(.(.{2})*)$/0\1/' -e 's/(.{2})/\\x\1/g')" \
    | openssl base64 -e

这变成:

echo 10001 | printf -- '\x01\x00\x01' | openssl base64 -e

哪个输出:

AQAB

推荐阅读