web-dev-qa-db-ja.com

Bashでは、文字列が何らかの値で始まっているかどうかをどうやって確認できますか?

文字列が "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

それを正しくするには?

606
Tim

高度なBashスクリプトガイド のこの抜粋は、/と言います。

# 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).

だからあなたはそれを持っていた ほぼ 正しい。シングルブラケットではなく、 double ブラケットが必要でした。


2番目の質問に関しては、このように書くことができます。

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)。

855
Mark Rushakoff

最近のbash(v3 +)を使っているのであれば、bash正規表現比較演算子=~をお勧めします。

if [[ "$Host" =~ ^user.* ]]; then
    echo "yes"
fi

正規表現でthis or thatと一致させるには、|を使用します。

if [[ "$Host" =~ ^user.*|^Host1 ]]; then
    echo "yes"
fi

注 - これは「適切な」正規表現構文です。

  • user*は、useと0回以上のrの出現を意味するため、useuserrrrは一致します。
  • user.*userと0以上の任意の文字の出現を意味するので、user1userXは一致します。
  • ^user.*は、$ Hostの先頭にあるパターンuser.*と一致することを意味します。

正規表現の構文に慣れていない場合は、 このリソース を参照してください。

注 - それぞれの新しい質問を新しい質問として尋ねると、stackoverflowがより整理され、より便利になります。参考のために、前の質問へのリンクをいつでも含めることができます。

169
brabster

スクリプティングの主なポイントの1つは移植性であるため、私はbashエクステンションを使用する代わりに常にPOSIX shに固執するようにしています。 ( 接続 プログラム以外に、それらを置き換えるのではありません)

Shでは、 "プレフィックス"条件を確認する簡単な方法があります。

case $Host in node*)
    your code here
esac

古くて難解なshが何歳であるか(そしてbashはそれほど良い方法ではありません。より複雑で一貫性がなく、移植性が低いです)から、casename__のような構文要素は組み込まれていますでは、結果として得られる構造は他のどの仕事と変わらない。それらは同じ方法で構成できます。

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 "[email protected]"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # prints TRUE
all "beginswith x" x xy abc ; checkresult  # prints FALSE

これはエレガントです。私はshを深刻な何かのために使うことを提唱するつもりはない - それは現実世界の要件をあまりにも早く壊してしまう(ラムダがないので、文字列を使わなければならない。

105
Jo So

確認したい文字列の部分だけを選択できます。

if [ ${Host:0:4} = user ]

フォローアップの質問には、 _または_ を使用できます。

if [[ $Host == user1 || $Host == node* ]]
67
martin clayton

私は他の方法がすでに投稿されているのを好むが、何人かの人々はそれを使いたがっている:

case "$Host" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

編集:

上記のcaseステートメントに代替案を追加しました

あなたの編集したバージョンでは、括弧が多すぎます。これは次のようになります。

if [[ $Host == user1 || $Host == node* ]];
55

私はここで大部分の答えがかなり正しいと思うが、それらの多くは不必要な根拠を含んでいます。 POSIXパラメータ展開 あなたが必要とするすべてをあなたに与える:

[ "${Host#user}" != "${Host}" ]

そして

[ "${Host#node}" != "${Host}" ]

${var#expr}は、exprと一致する最小のプレフィックスを${var}から取り除き、それを返します。したがって、${Host}usernode)で始まるnotである場合、${Host#user}${Host#node})は${Host}と同じです。

exprfnmatch() ワイルドカードを許可します。したがって${Host#node??}とその仲間も動作します。

28
dhke

#はbashで意味があるので、私は次の解決策を得ました。
さらに、スペースなどを克服するために、文字列を ""でパックする方が好きです。

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "skip comment line"
fi
28
ozma

@ 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

OR Bash 4.0

case "$Host" in
 user) ;& 
 node*) echo "ok";; 
esac
8
ghostdog74

Mark Rushakoffの最高ランクの回答に、もう少し構文の詳細を追加します。

表現

$Host == node*

と書くこともできます

$Host == "node"*

効果は同じです。ワイルドカードが引用テキストの外側にあることを確認してください。ワイルドカードが inside の引用符である場合、それは文字通りに解釈されます(すなわちワイルドカードとしてではありません)。

6
MrPotatoHead
if [ [[ $Host == user1 ]] -o [[ $Host == node* ]] ];  
then  
echo yes 
fi

[ [[ および test のすべてが同じ非再帰的な文法を認識するため、動作しません。 bashのmanページの 条件式 を参照してください。

余談ですが、SUSv3は言います

KornShell由来の条件付きコマンド(二重括弧 [[]] )は、初期の提案でシェルコマンド言語の説明から削除されました。本当の問題は test コマンド( [ )の誤用であり、それをシェルに入れることは問題を解決するのに間違った方法であるという反対意見が提起されました。代わりに、適切な文書と新しいシェル予約語()で十分です。

複数の test 操作が必要なテストは、エラーが発生しやすい -o フラグを使用するのではなく、 test コマンドおよびシェル論理を個別に呼び出すことによってシェルレベルで実行できます。 テスト

このように書く必要がありますが、 test はそれをサポートしていません。

if [ $Host == user1 -o $Host == node* ];  
then  
echo yes 
fi

test = を使用して文字列が等しい、より重要なことにはパターンマッチングをサポートしていません。

case/esacはパターンマッチングをうまくサポートしています。

case $Host in
user1|node*) echo yes ;;
esac

それはbashに依存しないという追加の利点があり、構文は移植可能です。 Single Unix Specification、シェルコマンド言語から:

case Word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac
6
just somebody

grep

パフォーマンスを忘れると、これはPOSIXであり、caseソリューションよりも見栄えがよくなります。

mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
  echo matches
fi

説明:

呼び出し可能な関数にするために@ 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
1
Mike Slinn