[英]In Bash, how can I check if a string begins with some value?
我想檢查一個字符串是否以“node”開頭,例如“node001”。 就像是
if [ $HOST == user* ]
then
echo yes
fi
我怎樣才能正確地做到這一點?
我還需要結合表達式來檢查 HOST 是“user1”還是以“node”開頭
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi
> > > -bash: [: too many arguments
我怎樣才能正確地做到這一點?
Advanced Bash Scripting Guide上的這個片段說:
# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.
[[ $a == z* ]] # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
所以你幾乎是正確的; 你需要雙括號,而不是單括號。
關於你的第二個問題,你可以這樣寫:
HOST=user1
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
echo yes1
fi
HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
echo yes2
fi
哪個會回響
yes1
yes2
Bash 的if
語法很難習慣(IMO)。
如果您使用的是最新版本的 Bash (v3+),我建議使用 Bash 正則表達式比較運算符=~
,例如,
if [[ "$HOST" =~ ^user.* ]]; then
echo "yes"
fi
要在正則表達式中匹配this or that
,請使用|
, 例如,
if [[ "$HOST" =~ ^user.*|^host1 ]]; then
echo "yes"
fi
注意 - 這是“正確的”正則表達式語法。
user*
表示use
和r
的零次或多次出現,因此use
和userrrr
將匹配。user.*
表示user
和零次或多次出現的任何字符,因此user1
, userX
將匹配。^user.*
表示匹配 $HOST 開頭的模式user.*
。如果您不熟悉正則表達式語法,請嘗試參考此資源。
請注意,Bash =~
運算符僅在右側為UNQUOTED時進行正則表達式匹配。 如果您確實引用了右側,則“可以引用模式的任何部分以強制將其作為字符串匹配。”。 即使在進行參數擴展時,也不應引用右側。
我總是嘗試堅持使用 POSIX sh
而不是使用 Bash 擴展,因為腳本的要點之一是可移植性(除了連接程序,而不是替換它們)。
在sh
中,有一種簡單的方法可以檢查“is-prefix”條件。
case $HOST in node*)
# Your code here
esac
考慮到 sh 有多古老、晦澀難懂(而且 Bash 不是靈丹妙葯:它更復雜、更不連貫且更不便攜),我想指出一個非常好的功能方面:雖然一些語法元素(如case
是內置的)在,由此產生的構造與任何其他工作沒有什么不同。 它們可以用相同的方式組成:
if case $HOST in node*) true;; *) false;; esac; then
# Your code here
fi
甚至更短
if case $HOST in node*) ;; *) false;; esac; then
# Your code here
fi
甚至更短(只是為了呈現!
作為語言元素——但現在這是不好的風格)
if ! case $HOST in node*) false;; esac; then
# Your code here
fi
如果您喜歡明確,請構建自己的語言元素:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
這真的不是很好嗎?
if beginswith node "$HOST"; then
# Your code here
fi
而且由於sh
基本上只是作業和字符串列表(以及內部進程,其中作業組成),我們現在甚至可以進行一些輕量級的函數式編程:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }
all() {
test=$1; shift
for i in "$@"; do
$test "$i" || return
done
}
all "beginswith x" x xy xyz ; checkresult # Prints TRUE
all "beginswith x" x xy abc ; checkresult # Prints FALSE
這是優雅的。 並不是說我主張將sh
用於任何嚴重的事情——它在現實世界的要求上太快了(沒有 lambda,所以我們必須使用字符串。但是用字符串嵌套函數調用是不可能的,管道是不可能的,等等)
您可以只選擇要檢查的字符串部分:
if [ "${HOST:0:4}" = user ]
對於您的后續問題,您可以使用OR :
if [[ "$HOST" == user1 || "$HOST" == node* ]]
我更喜歡已經發布的其他方法,但有些人喜歡使用:
case "$HOST" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
編輯:
我已將您的替代者添加到上面的案例陳述中
在您編輯的版本中,括號太多。 它應該如下所示:
if [[ $HOST == user1 || $HOST == node* ]];
雖然我發現這里的大多數答案都非常正確,但其中許多都包含不必要的 Bashisms。 POSIX 參數擴展為您提供所需的一切:
[ "${host#user}" != "${host}" ]
和
[ "${host#node}" != "${host}" ]
${var#expr}
從${var}
中去除與expr
匹配的最小前綴並返回它。 因此,如果${host}
不以user
( node
) 開頭,則${host#user}
( ${host#node}
) 與${host}
相同。
expr
允許fnmatch()
通配符,因此${host#node??}
和朋友也可以使用。
由於#
在 Bash 中具有含義,因此我得到了以下解決方案。
此外,我更喜歡用 "" 打包字符串以克服空格等。
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "Skip comment line"
fi
為 Mark Rushakoff 的最高等級答案添加一點點語法細節。
表達方式
$HOST == node*
也可以寫成
$HOST == "node"*
效果是一樣的。 只要確保通配符在引用的文本之外。 如果通配符在引號內,它將按字面意思解釋(即不作為通配符)。
@OP,對於您的兩個問題,您都可以使用 case/esac:
string="node001"
case "$string" in
node*) echo "found";;
* ) echo "no node";;
esac
第二個問題
case "$HOST" in
node*) echo "ok";;
user) echo "ok";;
esac
case "$HOST" in
node*|user) echo "ok";;
esac
或重擊 4.0
case "$HOST" in
user) ;&
node*) echo "ok";;
esac
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi
不起作用,因為所有[
、 [[
和test
都識別相同的非遞歸語法。 請參閱 Bash 手冊頁上的條件表達式部分。
順便說一句,SUSv3 說
在早期的提案中,KornShell 派生的條件命令(雙括號[[]] )已從 shell 命令語言描述中刪除。 有人提出反對,認為真正的問題是濫用測試命令 ( [ ),將其放入 shell 是解決問題的錯誤方法。 相反,適當的文檔和新的 shell 保留字 ( ! ) 就足夠了。
需要多個測試操作的測試可以在 shell 級別使用test命令和 shell 邏輯的單獨調用來完成,而不是使用test的容易出錯的-o標志。
你需要這樣寫,但test不支持它:
if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi
test使用=表示字符串相等,更重要的是它不支持模式匹配。
case
/ esac
對模式匹配有很好的支持:
case $HOST in
user1|node*) echo yes ;;
esac
它還有一個額外的好處是它不依賴於 Bash,並且語法是可移植的。 來自單一 Unix 規范, Shell 命令語言:
case word in
[(]pattern1) compound-list;;
[[(]pattern[ | pattern] ... ) compound-list;;] ...
[[(]pattern[ | pattern] ... ) compound-list]
esac
grep
忘記性能,這是 POSIX,看起來比case
解決方案更好:
mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
echo matches
fi
解釋:
printf '%s'
以防止printf
擴展反斜杠轉義: Bash printf 文字逐字字符串grep -q
防止匹配到標准輸出的回顯: 如何使用 Bash 檢查文件是否包含特定字符串grep -E
啟用擴展正則表達式,我們需要^
我調整了@markrushakoff 的答案,使其成為可調用函數:
function yesNo {
# Prompts user with $1, returns true if response starts with y or Y or is empty string
read -e -p "
$1 [Y/n] " YN
[[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}
像這樣使用它:
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] Y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] yes
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n]
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] ddddd
false
這是一個提供指定默認值的更復雜的版本:
function toLowerCase {
echo "$1" | tr '[:upper:]' '[:lower:]'
}
function yesNo {
# $1: user prompt
# $2: default value (assumed to be Y if not specified)
# Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string
local DEFAULT=yes
if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
if [[ "$DEFAULT" == y* ]]; then
local PROMPT="[Y/n]"
else
local PROMPT="[y/N]"
fi
read -e -p "
$1 $PROMPT " YN
YN="$( toLowerCase "$YN" )"
{ [ "$YN" == "" ] && [[ "$PROMPT" = *Y* ]]; } || [[ "$YN" = y* ]]
}
像這樣使用它:
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N]
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N] y
true
$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false
把事情簡單化
word="appel"
if [[ $word = a* ]]
then
echo "Starts with a"
else
echo "No match"
fi
你可以做的另一件事是cat
出你是什么呼應和管道與inline cut -c 1-1
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.