什么是POSIX shell中等效于bash <<< 的命令?

15

我有一个变量长得像这样:

msg="newton apple tree"

我想将这些单词分别赋值给不同的变量。在Bash中,这很容易实现:

read a b c <<< $msg

在 POSIX shell 中,有没有一种紧凑易读的方法来完成这个任务?


您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - hardmath
2
如果存在 POSIX sh(您可能并不真正意味着 Bourne - Bourne 是 70 年代的一种 shell;除非您正在使用相对较旧的 Solaris,否则没有人使用 Bourne),那么为什么 bash 必须引入该功能? - Charles Duffy
1
没错 - 这不起作用,因为管道会创建一个子shell,并且变量的值仅限于该子shell。 - Charles Duffy
1
如果您要立即使用它们,可以使用 echo "$msg" | { read a b c; do_something_with "$a"; },但是当管道关闭时,这些值仍然未设置。 - Charles Duffy
1
顺便说一句,你可能会对http://mywiki.wooledge.org/BashFAQ/024感兴趣——它涵盖了纯POSIX、ksh等的行为,以及bash。 - Charles Duffy
显示剩余3条评论
3个回答

31

一个Here字符串只是单行Here文档的一种语法糖:

$ msg="foo * bar"
$ read a b c <<EOF
> $msg
> EOF
$ echo "$a"
foo
$ echo "$b"
*
$ echo "$c"
bar

我有一个包含文本的变量 - 每行一个句子。当我尝试您的示例时,它只能读取第一行,即仅显示echo "$a"的输出。其他行被省略了。例如,echo "$b"为空。 - t7e
字符串 由多行组成,但 read 只读取其中一行。如果你想从 here-string 中读取三行,你需要三个单独的 read 命令,例如 { read a; read b; read c; } <<< "$FOO" - chepner
1
这不是Bash特有的功能;它被POSIX支持。 - chepner
非常有帮助。如果您不介意,我会将这个答案添加到这个主题中。 - t7e
1
从标准输入读取两行与所提问的问题无关。 - chepner
显示剩余6条评论

11

要撰写通顺的脚本,不能仅仅查看每个语法单元并尝试找到与 POSIX 相对应的等效项。这就像通过用字典中每个单词的条目替换每个单词来翻译文本。

将已知有三个单词的字符串拆分为三个参数的 POSIX 方式类似但不完全相同于 read

var="newton apple tree"

set -f
set -- $var
set +f
a=$1 b=$2 c=$3

echo "$a was hit by an $b under a $c"

1
我可能会在一个函数中完成这项工作,以避免覆盖全局变量 $@,但这是一个很好的解决方案。 - Charles Duffy
4
这样做会不必要地覆盖位置参数;这里字符串只是单行文档的快捷方式,因此无需用set命令替换read - chepner

6
作为一个通用解决方案,它并不美观,但您可以通过命名管道来解决这个问题。
来自BashFAQ #24
mkfifo mypipe
printf '%s\n' "$msg" >mypipe &
read -r a b c <mypipe

printfecho更可靠/规范; 如果您有一个仅包含-E-n的消息,echo的行为会因实现而异。


话虽如此,针对你在这里所做的事情,你可以只使用参数扩展:

a=${msg%% *}; msg=${msg#* }
b=${msg%% *}; msg=${msg#* }
c=${msg%% *}; msg=${msg#* }

我认为你需要添加“a b c”而不是这一行,以使它更符合我的例子。但是,这看起来像一个可能的答案。 - Bitdiot
啊,好的,看起来更好了。 - Bitdiot
我想给你看看,但我觉得那个人有一个更优雅的解决方案。希望你不介意。 - Bitdiot
1
@Bitdiot,这绝对是一个更优雅的解决方案;他得到了我的支持。我只是将其保留在原地,因为它适用于其他不太合适的情况(例如处理多行)。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接