Shell

測試變數是否包含換行符(POSIX)

  • June 5, 2018

我知道有些 shell 接受這種測試:

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

您可以在變數中放置一個硬換行符,並使用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}

明顯的命令替換不起作用,因為替換刪除了尾隨換行符。

是的,

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 字節(沒有外殼但zsh可以儲存在它們的變數中)之外,*$nl*應該匹配任何包含的字元串,$nl即使它們包含不形成有效的字節序列字元(如$'\x80'在 UTF-8 中)。

例如,某些find實現將無法與-name "*$nl*"它們匹配,因此如果測試一個新的 shell,並且如果您打算處理不能保證是文本的內容(如文件名),您可能需要為其添加一個測試案例。與:

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

在 UTF-8 語言環境中。

引用自:https://unix.stackexchange.com/questions/421898