我想从 ksh 脚本中 3 个不同变量的变量中提取 3 个单词。我在 ksh93 上使用了这条线,效果很好:
read A B C <<< $line
在 ksh88 上运行上述命令时出现此错误:
syntax error at line ## : '<' unexpected
如何在 ksh88 上执行相同的操作?
mir*_*los 13
不,这里的字符串在ksh88
和上不可用pdksh
。但是,在最近的ksh93
(原始 AT&T Korn Shell)和mksh
(当前积极开发的pdksh
衍生产品)上,它是可用的。
<<<
是ksh93
, mksh
, GNUbash
和zsh
.
您的具体问题...
read A B C <<< $line
Run Code Online (Sandbox Code Playgroud)
...可以解决这个问题(Korn shell):
print -r -- $line |&
read -p A B C
Run Code Online (Sandbox Code Playgroud)
你也可以使用这个(POSIX shell),虽然它有 tmpfile 性能损失(另一方面,<<<
可能也有):
read A B C <<EOF
$line
EOF
Run Code Online (Sandbox Code Playgroud)
但是,如果您只想拆分单词:
set -A arrname -- $line
Run Code Online (Sandbox Code Playgroud)
然后使用${arrname[0]}
代替$A
和${arrname[1]}
代替$B
。只有它不会停止在三个元素处进行拆分,因此如果$line
是“ foo bar baz bla
”,$C
将包含“baz bla”,而${arrname[2]}
具有“baz”并${arrname[3]}
具有“bla”。
但是,如果您不需要位置参数,则可以执行
set -- $line
A=$1; shift
B=$1; shift
C=$*
Run Code Online (Sandbox Code Playgroud)
但是,shift
如果$line
少于三个单词,则会导致错误(检查$#
您是否不确定,或者使用[[ $line = *' '*' '[! ] ]]
(虽然可能较慢)先检查)。
Mind that set … $line
will also do globbing(感谢 Stéphane 提醒我们),所以你需要set -o noglob
之前(并且可能在之后恢复之前的状态,通常是set +o noglob
)。
完全披露:我是mksh
开发人员。
不,here-strings 来自zsh
1991 年的 2.0(和/或 Unix 端口rc
,他们各自的作者在那个时候交换了想法,不清楚两者中的哪一个有这个想法或首先将它包含在他的 shell 中)。
它在 2.05b (2002) 中被添加到 bash、m+ (2002) 中的 ksh93、R33 (2008) 中的 mksh、2.7 (2009) 中的 yash。
ksh88 没有获得任何新功能。
这里的文档 ( <<
) 本身来自 70 年代后期的 Bourne-shell。
read A B C
以一种非常特殊的方式将一个逻辑行读入A
,B
和C
变量(有点不那么特殊,它的默认值$IFS
只包含 IFS 空白字符¹),反斜杠充当转义和行继续符以及将要发生的事情C
也相当复杂。在没有的情况下做同样的事情read
会很困难。
无论如何,这里<<<
与 相同<<
,仅在语法上有所不同。
read A B C << EOF
$var
EOF
Run Code Online (Sandbox Code Playgroud)
完全一样
read A B C <<< "$var" # note that some versions of bash need the quotes
Run Code Online (Sandbox Code Playgroud)
在所有贝壳中。对于这两种情况,shell 创建一个已删除的临时文件,其中包含内容和一个额外的换行符(尽管有些 shell 使用管道代替)。然后read
从中读取一个逻辑行(可能在多条物理行上以反斜杠继续)并使用其复杂规则填充变量。
它仅分配第一3个字(SPC /制表符分隔)的$var
对$A
,$B
并且 $C
如果
$IFS
仍然包含其默认值对于前三个词,你可以这样做:
function split_into {
typeset words IFS v i=0
set -o noglob
set -A words -- $1; shift
for v do
eval "$v=\${words[i]}"
((i += 1))
done
}
split_into "$var" A B C
Run Code Online (Sandbox Code Playgroud)
¹ IFS 空白字符,每个 POSIX 是[:space:]
在语言环境中分类的字符,$IFS
尽管在 ksh88(POSIX 规范所基于的)和大多数 shell 中,这仍然仅限于 SPC、TAB 和 NL。我发现在这方面唯一符合 POSIX 的 shell 是yash
. ksh93
并且bash
(从 5.0 开始)还包括其他空格(例如 CR、FF、VT...),但仅限于单字节(在某些系统上(例如 Solaris)要小心,其中包括单字节的不间断空格在某些地区)