微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Linux Shell“粘贴”命令 - 保证基于行的交错?

如何解决Linux Shell“粘贴”命令 - 保证基于行的交错?

我在 Linux shell (paste) 中使用 bash 命令,目的是在每行的基础上交错两个命令的输出。根据经验,我的代码似乎有效,但我想知道 paste 是否保证了每个命令的交替输出行的行为。如果我运行下面的代码 100 次,并且其中一个命令的运行速度比另一个命令慢,我能否在另一个命令赶上之前从一个命令获得两行输出?我在系统(OS X 或 Ubuntu 18.04)的 man 页面中没有看到任何相关文档,它似乎可以正常工作...

找到下面的示例代码(仅供参考,它以我喜欢的格式生成格式化的十六进制转储):

# Version 1
paste -d "\n" <(
    cat "${largeFile}" | 
    LC_CTYPE=C tr -c '[:print:]' '.' | 
    sed -E $'s/.{30}/&\\\n/g' | 
    sed 's/./&  /g'
) <(
    xxd -p "${largeFile}" |
    sed 's/../& /g'
)

输出

G  I  F  8  9  a  .  .  q  .  w  .  .  !  .  3  C  r  e  a  t  e  d     w  i  t  h     t  
47 49 46 38 39 61 c7 01 71 00 77 ff 00 21 fe 33 43 72 65 61 74 65 64 20 77 69 74 68 20 74 
...

当你给它两个流时,这个问题有点与 cat 的行为相反:cat 名义上首先从一个流打印(可能是它的所有行),然后是另一个。例如:

# Echo buffers at 8096 characters on my system
numLines=$(( 2 * (8096 + 36) / 37 ))

# Make some dummy text that is double the size of echo's buffer
longText1="$( seq -f "Line %04.0f: $( printf "%s" {a..z} )" 1 ${numLines} )"
longText2="$( seq -f "Line %04.0f: $( printf "%s" {A..Z} )" 1 ${numLines} )"

# Print two streams simultaneously and check for interleaving
cat <(echo "${longText1}") <(echo "${longText2}")

上面的代码首先“大部分时间”打印 longText1(小写字母)中的所有行,然后是 longText2(大写字母)中的文本。但是,如果您运行它的次数足够多,则情况并非总是如此。请参阅此帖子:https://unix.stackexchange.com/a/476089/464414

因此,对于 cat,两个流的交错行为实际上是未定义的,但根据经验测试,您可以很容易地猜测该行为是“不交错”。 paste 的情况如何——行为是否有保证?我很担心,因为我没有看到 man 页面中写的任何内容


侧边栏

如果有人在这文章搜索关键字“hexdump 格式”或其他内容,这里是代码的另一个版本,有时运行速度会更快一些。仅在答案说它安全时才使用;-)

# Version 2
paste -d "\n" <(
    cat "${largeFile}" | 
    LC_CTYPE=C tr -c '[[:print:]]' '.' | 
    fold -bw 1 | 
    tr "\n" " " | 
    fold -bw 2 | 
    tr "\n" " " | 
    fold -bw 90
) <(
    xxd -p "${largeFile}" | 
    fold -bw2 | 
    tr -s "\n" " " | 
    fold -bw 90
)

或者:

formatAscii=\
'/0 "%010_ad  |\t" '\
'30/1 " %_p " '\
'"\n"'
formatHex=\
'/0 "%010_ad  |\t" '\
'30/1 "%02x " '\
'"\n"'
hexdump -v -e "${formatAscii}" -e "${formatHex}" "${largeFile}"

解决方法

保证基于行的交错?

GNU 工具已获得任何 GPL 许可,但不提供任何形式的保证。 BSD 实用程序受 BSD 许可,也不提供任何形式的保证。有许可的 POSIX 操作系统可以为您提供行为保证。

保证基于行的交错?

没有任何形式的保证。是的,这就是该实用程序的工作方式。

如果你运行它的次数足够多,那并不总是正确的

除非宇宙射线或其他极不可能的事件不会干扰您的硬件,否则总是如此。

行为是否有保证?

没有任何形式的保证。是的,这就是它的工作原理。


您使用的所有程序、外壳和内核都是开源的。检查它们的来源以熟悉它们的工作方式。

标准实用程序的“最重要”描述在 POSIX 中,请参阅 POSIX catPOSIX paste

,

我想知道 paste 是否保证了每个命令的交替输出行的行为

这就是 paste 应该如何工作的定义,它不能那样工作的唯一原因是您的 paste 命令被破坏,即它不符合 {{ 3}} 表示“粘贴实用程序应连接给定输入文件的相应行,并将结果行写入标准输出。”

换句话说paste file1 file2从file1中读取一行,从file2中读取一行,然后输出两行的连接,然后对下一行重复这些操作。

如果 (...) 一个命令的运行速度比另一个慢,我能否在另一个命令赶上之前从一个命令获得两行输出?

没有。 paste file1 file2 总是按照输入文件的顺序(file1 然后file2)进行连接,并且它总是在从每个输入文件中读取一行之后才进行连接。

唯一预期的例外是当满足 EOF 时(一个文件的行数比另一个文件少)并且行为由 POSIX 很好地定义:“如果在一个或多个输入文件上检测到文件结束条件,但是并非所有输入文件,粘贴的行为就像从检测到文件结尾的文件中读取空行一样"

我在系统的手册页中没有看到任何相关文档

如果一行需要时间来读取,paste 将等待直到它完全可用(即直到结束 \n 已被读取或满足 EOF)。当您的手册页指出“xxx 读取一行输入”时,这是预期的行为。如果有超时或任何可能破坏正常行为的特殊情况(即使读取中止),则并且只有在此之后手册中才会提及。

当你给它两个流时,这个问题有点与 cat 的行为相反:cat 名义上首先从一个流打印(可能是它的所有行),然后是另一个。

是的,这就是在 the POSIX standard 中定义 cat 的方式:“cat 实用程序应按顺序读取文件并将其内容以相同的顺序写入标准输出。”

但如果你运行它的次数足够多,那并不总是正确的。

没有。您可能会运行 cat 100 亿次,它将始终按照 POSIX 的定义运行。如果您的 cat file1 file2 有时在 file1 之前输出 file2,那么您的 cat 已损坏。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。