zsh:从标准输入读取直到字符串分隔符

zsh:从标准输入读取直到字符串分隔符

我想从遇到stdin字符串分隔符开始读取MARKER=$'\0'"BRISH_MARKER"。我试过:

❯ unset br ; print -rn -- hi${MARKER}world |   {  IFS= read -d "$MARKER" -r br ; cat -v } ; echo ; typeset -p br

这使:

BRISH_MARKERworld
typeset br=hi

因此read仅使用给定分隔符的第一个字符\0。我希望它使用整个字符串。我怎样才能实现这个目标?

我试图解决的问题是,我有一个进程不断地将数据流提供给 zsh 进程,并且需要使用分隔符将数据分解为不同的值。我最初只使用\0,但这不允许我使用包含 的值\0,所以我尝试使用当前的MARKER.

答案1

Yesread -d仅适用于单字符分隔符(在bash和中ksh93,它仅适用于单字符分隔符)字节分隔符)。

读取到定界符还意味着您需要一次读取一个字节(尤其是对于不可查找的输入,例如管道)以确保您不会读取过去的分隔符,这使得它效率低下。

我建议使用length:value记录代替:

write-record() {
  set -o localoptions +o multibyte
  print -rn -- "$#1:$1"
}
read-record() {
  set -o localoptions +o multibyte
  local len

  # note that in current versions of zsh, read -k0 (for empty records)
  # returns a non-zero exit status.
  eval "$1="
  IFS= read -rd: len || return
  ((len == 0)) || read -u0 -k "$len" "$1"
}

multibyte在本地禁用那些以字节为单位的长度,并避免此处无用的字符编码/解码)。

那么作为一个例子:

$ (write-record $'é\0x'; write-record $'foo\0MARKER') | { read-record a && read-record b; printf "<%q>\n" "$a" "$b"; }
<é$'\0'x>
<foo$'\0'MARKER>

相关内容