逐行遍历多行字符串

Ste*_*ner 2 shell

我想/bin/sh在 BSD 平台上的POSIX shell ( ) 中处理多行字符串并逐行迭代它。Bash 不包含在基本的 BSD 发行版中,并且拥有 GPL 许可证——所以我试图让它普遍使用/bin/sh

我找到了一个使用管道的解决方案,但是在常规/bin/shshell 中,这些是在单独的进程中处理的,这意味着以下内容不起作用:

MULTILINE="`cat ${SOMEFILE}`"
SOMEVAR="original value"

echo "${MULTILINE}" | while IFS= read -r SINGLELINE
do
 SOMEVAR="updated value"
 echo "this is a single line: ${SINGLELINE}"
 echo "SOMEVAR is now: ${SOMEVAR}"
done

echo "Final SOMEVAR is unchanged: ${SOMEVAR}"
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,它完成了我想要的,除了${SOMEVAR}在 while 循环之外无法访问对诸如此类的变量的更改这一事实。

我的问题:如何在没有此限制的情况下完成上述操作?请注意,许多解决方案需要 Bash,而我使用的是标准 POSIX-shell /bin/sh

Sté*_*las 5

您可以使用此处的文档:

while IFS= read -r SINGLELINE
do
  SOMEVAR="updated value"
  printf '%s\n' "this is a single line: ${SINGLELINE}"
  printf '%s\n' "SOMEVAR is now: ${SOMEVAR}"
done << EOF
$MULTILINE
EOF
printf '%s\n' "Final SOMEVAL is still $SOMEVAR"
Run Code Online (Sandbox Code Playgroud)

根据sh实现,here-documents 要么被实现为一个已删除的临时文件,其中 shell 已经存储了变量的扩展,然后是换行符,或者是一个管道,shell 将变量的扩展提供给它,然后是换行符。但在任何一种情况下,除了原始 Bourne shell(现在不再使用的 shell,并且不是 POSIX 兼容的 shell),被重定向的命令不会在子 shell 中运行(如 POSIX 要求)。

或者你可以使用 split+glob:

IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
  SOMEVAR="updated value"
  printf '%s\n' "this is a single line: ${SINGLELINE}"
  printf '%s\n' "SOMEVAR is now: ${SOMEVAR}"
done
printf '%s\n' "Final SOMEVAL is still $SOMEVAR"
Run Code Online (Sandbox Code Playgroud)

但要注意它会跳过空行。