Shell-Script

如何檢查字元串是否包含破折號或灰燼中的子字元串?

  • December 2, 2020

這是我正在嘗試的內容:

#!/bin/sh
contains() {
   if $(echo $1 | grep -c $2) ; then
       echo "0" # contains
   else
       echo "1" # not contains
   fi
}

myString=$1
mySubsting=$2

contains $myString '$mySubsting'

下面是一個執行範例:

# sh ./myScript abcdef bc
./myTest: line 3: 0: command not found
1

編輯:

最初的問題是:如何在 Bourne Shell 中檢查字元串是否包含子字元串?

這是我正在嘗試的內容:

 #!/bin/sh
 if echo $1 | grep -q $2
 then
   echo "0"
 else
   echo "1"
 fi

下面是一個執行範例:

$ sh ./myTest "$(systemctl status ntp)" "Active: active"
grep: active: No such file or directory
1

如何正確檢查一個字元串是否包含另一個字元串?

Bourne shell 有一個結構。這與現代相同sh(這看起來更像您正在使用的,Bourne shell 不支持$(...);如果它是 Bourne shell,您會得到一個不同的錯誤):

case $1 in
 *"$2"*) printf '"%s" is in "%s"\n' "$2" "$1"
esac

如果您想使用grep,那將是:

if printf '%s\n' "$1" | grep -Fqe "$2"; then
 printf '"%s" is in "%s"\n' "$2" "$1"
fi

或者

if grep -Fqe "$2" << EOF
$1
EOF
then
 printf '"%s" is in "%s"\n' "$2" "$1"
fi

但這只有在$2不包含換行符的情況下才能正常工作。

在任何情況下,您都需要在大多數參數擴展周圍加上引號。唯一不需要它的地方是在case $1上面,但即使那樣case "$1"也不會有害。

關於您的程式碼的一些註釋:

  1. 您不能echo用於任意字元串。在這裡,取決於實現,對於like或echo的值,它會失敗。$1``-n``foo\bar
  2. 不加引號的參數擴展在 shell 中具有非常特殊的含義。你不想那樣做。例如,嘗試使用like或grep -c $2的值。$2``*``root /etc/passwd
  3. grepwithout-F用於正則表達式匹配。您需要-F固定字元串(子字元串)搜尋(曾經是 with fgrep),但如果$2包含多行,則表示grep -F要搜尋輸入中這些行的任何grep -F $'a\nb'內容(將查找aor b,而不是$'a\nb'字元串)。
  4. 在中,如果以 開頭grep -c $2,則 的內容$2將被視為一個選項-。你想要grep -c -e "$2"grep -c -- "$2"避免這種情況。
  5. 您想使用退出狀態,而不是標準輸出來報告布爾條件。在帶有exit(exit 0代表真,exit 1(或任何非零數字,但避免值大於 120)代表假)的腳本中。對於函式,請return改用。儘管腳本和函式都將返回上次執行命令的狀態。
  6. $(cmd) 擴展cmd(並且由於再次缺少引號而在此處經歷 split+glob)減去尾隨換行符的輸出。因此,如果cmd輸出0\n,則$(cmd)擴展為0。因此 running$(cmd)會嘗試執行名為0. 如果您想將輸出轉換為cmd退出狀態(因此它可以用作布爾值),您需要(exit "$(cmd)"). 這將啟動一個子shell,該子shell 以 的輸出cmd作為其退出程式碼)。
  7. grep -c計算出現次數。在這裡,您不需要完整計數,您只需要知道是否找到它(如果至少有一個匹配項)。因為grep -q它在找到一個後停止搜尋,因此效率更高。grep對於不支持 (standard) 選項的古老實現-q,您可以使用fgrep -le "$2" > /dev/null. 使用-l,fgrep在第一次匹配時也停止,但輸出文件名(我們在這里通過將輸出重定向到 丟棄/dev/null)。

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