测试变量是否包含换行符(POSIX)


8

我知道有些外壳接受这种测试:

t() { [[ $var == *$'\n'* ]] && res=yes || res=no
      printf '%s ' "$res";
    }

var='ab
cd'
t
var='abcd'
t
echo

执行时:

$ bash ./script
yes no
  1. 什么是POSIX(破折号)工作等效项

  2. 以下是可靠的测试方法吗?

    nl='
    '
    
    t() {  case "$var" in
               *$nl* ) res=yes ;;
               * ) res=no ;;
           esac
           printf '%s ' "$res"
         }
    
    var='ab
    cd'
    t
    var='abcd'
    t
    echo
    

Answers:


12

您可以在变量中加入硬换行符,然后使用进行模式匹配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}

明显的命令替换不起作用,因为尾随换行符被替换删除。


5

是,

nl='
'
case $var in
  (*"$nl"*) echo yes;;
  (*)       echo no;;
esac

(原则上,case除非希望将它们视为模式,否则我喜欢在pattern 内引用所有变量扩展,尽管此处$nl不包含通配符,但这并没有区别)。

要么

case $var in
  (*'
'*) echo yes;;
  (*) echo no;;
esac

应该都能正常工作并且符合POSIX,以及我要使用的东西。如果删除(s,它甚至可以在旧的Bourne shell中运行。

另一种设置$nl变量的方式:

eval "$(printf 'nl="\n"')"

请注意,$'\n'计划将其包含在POSIX标准的下一版本中。它已经被支持ksh93zshbashmksh,busybox的和FreeBSD sh至少(2月2018)。

至于您所进行的测试是否足够,您已经针对两种情况进行了测试,因此将测试所有代码路径。

当前在POSIX规范中没有明确指定的内容:是否*匹配包含不构成有效字符的字节序列的字符串,或者shell变量是否可以包含这些字符串。

在实践中,除了yash其变量只能包含字符之外,并且与NUL字节(没有外壳,但zsh可以存储在其变量中)不同,即使包含不合法字节序列的*$nl*字符串也应匹配$nl字符(如$'\x80'UTF-8)。

find例如,某些实现将无法与-name "*$nl*"它们匹配,因此,如果测试新的Shell,并且打算处理不能保证是文本的事物(如文件名),则可能需要为其添加测试用例。搭配:

test=$(printf '\200\n\200')

在UTF-8语言环境中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.