我知道有些 shell 接受这种测试:
t() { [[ $var == *$'\n'* ]] && res=yes || res=no
printf '%s ' "$res";
}
var='ab
cd'
t
var='abcd'
t
echo
执行时:
$ bash ./script
yes no
POSIX(破折号)的等效工作是什么
以下测试方法可靠吗?
nl=' ' t() { case "$var" in *$nl* ) res=yes ;; * ) res=no ;; esac printf '%s ' "$res" } var='ab cd' t var='abcd' t echo
答案1
您可以在变量中放置硬换行符,并与 进行模式匹配case
。
$ cat nl.sh
#!/bin/sh
nl='
'
case "$1" in
*$nl*) echo has newline ;;
*) echo no newline ;;
esac
$ dash nl.sh $'foo\nbar'
has newline
$ dash nl.sh $'foobar'
no newline
制作换行符的另一种方法是这样的:
nl=$(printf "\nx"); nl=${nl%x}
明显的命令替换不起作用,因为替换会删除尾随换行符。
答案2
是的,
nl='
'
case $var in
(*"$nl"*) echo yes;;
(*) echo no;;
esac
(原则上,我喜欢引用case
模式内的所有变量扩展,除非我希望将它们视为模式,尽管在这里它没有什么区别,因为$nl
不包含通配符)。
或者
case $var in
(*'
'*) echo yes;;
(*) echo no;;
esac
应该一切正常并且符合 POSIX 标准,以及我将使用什么。如果删除(
s,它甚至可以在旧的 Bourne shell 中工作。
设置$nl
变量的另一种方法:
eval "$(printf 'nl="\n"')"
注意$'\n'
计划包含在下一版本的 POSIX 标准中。至少已经被ksh93
、zsh
、bash
、mksh
busybox 和 FreeBSD支持(截至 2018 年 2 月)。sh
至于您拥有的测试是否足够,您已经对两种情况进行了测试,因此将测试所有代码路径。
目前 POSIX 规范中还没有明确指定一些内容:是否*
匹配包含不形成有效字符的字节序列的字符串,或者 shell 变量是否可以包含这些字符串。
实际上,除了yash
变量只能包含字符之外,除了 NUL 字节(没有 shell 但zsh
可以存储在变量中)之外,*$nl*
应该匹配任何包含的字符串,$nl
即使它们包含不形成有效的字节序列字符(如$'\x80'
UTF-8)。
例如,某些find
实现将无法与-name "*$nl*"
它们匹配,因此如果测试新的 shell,并且您打算处理不能保证是文本的内容(例如文件名),您可能需要为其添加一个测试用例。喜欢与:
test=$(printf '\200\n\200')
在 UTF-8 语言环境中。