Ich möchte überprüfen, ob eine Zeichenfolge mit "node" beginnt, z. "node001". So etwas wie
if [ $Host == user* ]
then
echo yes
fi
Wie kann ich das richtig machen?
Ich muss außerdem Ausdrücke kombinieren, um zu überprüfen, ob Host entweder "user1" ist oder mit "node" beginnt.
if [ [[ $Host == user1 ]] -o [[ $Host == node* ]] ];
then
echo yes
fi
> > > -bash: [: too many arguments
Wie mache ich es richtig?
Dieses Snippet im Advanced Bash Scripting Guide sagt:
# 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).
Sie hatten es also fast richtig; Sie brauchten doppelte Klammern, keine einfachen Klammern.
In Bezug auf Ihre zweite Frage können Sie es so schreiben:
Host=user1
if [[ $Host == user1 ]] || [[ $Host == node* ]] ;
then
echo yes1
fi
Host=node001
if [[ $Host == user1 ]] || [[ $Host == node* ]] ;
then
echo yes2
fi
Welches wird echo
yes1
yes2
Bashs if
Syntax ist schwer zu gewöhnen (IMO).
Wenn Sie eine kürzliche Bash (v3 +) verwenden, empfehle ich den Bash-Regex-Vergleichsoperator =~
, d. H.
if [[ "$Host" =~ ^user.* ]]; then
echo "yes"
fi
Um this or that
in einem regulären Ausdruck abzugleichen, verwenden Sie |
, d.h.
if [[ "$Host" =~ ^user.*|^Host1 ]]; then
echo "yes"
fi
Hinweis - Dies ist die richtige Syntax für reguläre Ausdrücke.
user*
bedeutet use
und null oder mehr Vorkommen von r
, daher stimmen use
und userrrr
überein.user.*
bedeutet user
und null oder mehr Vorkommen eines beliebigen Zeichens, daher stimmen user1
, userX
überein.^user.*
bedeutet Übereinstimmung mit dem Muster user.*
am Anfang von $ Host.Wenn Sie mit der Syntax regulärer Ausdrücke nicht vertraut sind, lesen Sie diese Ressource .
Hinweis - Es ist besser, wenn Sie jede neue Frage als neue Frage stellen. Dadurch wird der Stapelüberlauf übersichtlicher und nützlicher. Sie können jederzeit einen Link zu einer vorherigen Frage als Referenz einfügen.
Ich versuche immer, mich an POSIX sh zu halten, anstatt Bash-Erweiterungen zu verwenden, da einer der Hauptaspekte der Skripterstellung die Portabilität ist. (Außerdem Verbinden Programme, die nicht ersetzt werden)
In sh gibt es eine einfache Möglichkeit, nach einer "is-prefix" -Zustand zu suchen.
case $Host in node*)
your code here
esac
In Anbetracht dessen, wie alt, arkan und crufty sh ist (und Bash ist nicht die Heilung: Es ist komplizierter, weniger konsistent und weniger portabel), möchte ich auf einen sehr schönen funktionalen Aspekt hinweisen: Während einige Syntaxelemente wie case
sind integriert, die resultierenden Konstrukte unterscheiden sich nicht von anderen Jobs. Sie können auf die gleiche Weise zusammengesetzt werden:
if case $Host in node*) true;; *) false;; esac; then
your code here
fi
Oder noch kürzer
if case $Host in node*) ;; *) false;; esac; then
your code here
fi
Oder sogar kürzer (nur um !
als Sprachelement zu präsentieren - aber das ist jetzt ein schlechter Stil)
if ! case $Host in node*) false;; esac; then
your code here
fi
Wenn Sie explizit sein möchten, erstellen Sie Ihr eigenes Sprachelement:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Ist das nicht wirklich ganz nett?
if beginswith node "$Host"; then
your code here
fi
Und da es sich bei sh im Grunde nur um Jobs und String-Listen (und interne Prozesse, aus denen sich Jobs zusammensetzen) handelt, können wir jetzt sogar einige leichte funktionale Programmierungen durchführen:
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
Das ist elegant. Nicht, dass ich es befürworten würde, sh für irgendetwas Ernstes zu verwenden - es bricht allzu schnell unter realen Bedingungen (keine Lambdas, daher müssen Strings verwendet werden. Es ist jedoch nicht möglich, Funktionsaufrufe mit Strings zu verschachteln, Pipes sind nicht möglich ...)
Sie können nur den Teil der Zeichenfolge auswählen, den Sie überprüfen möchten:
if [ ${Host:0:4} = user ]
Für Ihre Folgefrage können Sie ein ODER verwenden:
if [[ $Host == user1 || $Host == node* ]]
Ich bevorzuge die anderen Methoden, die bereits veröffentlicht wurden, aber einige Leute verwenden sie gerne:
case "$Host" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
Bearbeiten:
Ich habe Ihre Stellvertreter zur obigen case-Anweisung hinzugefügt
In Ihrer bearbeiteten Version haben Sie zu viele Klammern. Es sollte so aussehen:
if [[ $Host == user1 || $Host == node* ]];
Während ich die meisten Antworten hier ziemlich richtig finde, enthalten viele von ihnen unnötige Bashismen. POSIX-Parametererweiterung gibt Ihnen alles, was Sie brauchen:
[ "${Host#user}" != "${Host}" ]
und
[ "${Host#node}" != "${Host}" ]
${var#expr}
entfernt das kleinste passende Präfix expr
aus ${var}
und gibt dieses zurück. Wenn also ${Host}
nicht mit user
(node
) beginnt, ist ${Host#user}
(${Host#node}
) dasselbe wie ${Host}
.
expr
erlaubt fnmatch()
Platzhalter, daher funktionieren ${Host#node??}
und Freunde auch.
da # in bash eine bedeutung hat, bin ich zu folgender lösung gekommen.
Außerdem packe ich lieber Strings mit "", um Leerzeichen usw. zu überwinden.
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "skip comment line"
fi
Mark Rushakoffs ranghöchste Antwort wurde um ein wenig mehr Syntaxdetails erweitert.
Der Ausdruck
$Host == node*
Kann auch geschrieben werden als
$Host == "node"*
Der Effekt ist der gleiche. Stellen Sie einfach sicher, dass sich der Platzhalter außerhalb des angegebenen Texts befindet. Wenn der Platzhalter innen ist, werden die Anführungszeichen wörtlich interpretiert (d. H. Nicht als Platzhalter).
@OP, für beide Fragen kannst du case/esac verwenden
string="node001"
case "$string" in
node*) echo "found";;
* ) echo "no node";;
esac
zweite Frage
case "$Host" in
node*) echo "ok";;
user) echo "ok";;
esac
case "$Host" in
node*|user) echo "ok";;
esac
ODER Bash 4.0
case "$Host" in
user) ;&
node*) echo "ok";;
esac
if [ [[ $Host == user1 ]] -o [[ $Host == node* ]] ];
then
echo yes
fi
funktioniert nicht, da alle von [, [[ und test erkenne die gleiche nichtrekursive Grammatik. Siehe Abschnitt CONDITIONAL EXPRESSIONS in Ihrer Bash-Manpage.
Nebenbei bemerkt, sagt der SUSv3
Der von KornShell abgeleitete bedingte Befehl (doppelte Klammer [[]]) wurde in einem frühen Vorschlag aus der Beschreibung der Shell-Befehlssprache entfernt. Es wurden Einwände erhoben, dass das eigentliche Problem der Missbrauch des Befehls test ([) ist, und dass das Einfügen in die Shell der falsche Weg ist, um das Problem zu beheben . Stattdessen reichen eine ordnungsgemäße Dokumentation und ein neues Shell-reserviertes Wort (!) aus.
Tests, die mehrere Testoperationen erfordern, können auf Shell-Ebene ausgeführt werden, indem einzelne Aufrufe des Befehls test und der Shell-Logik anstelle von ausgeführt werden mit dem fehleranfälligen - o Flag von test .
sie müssten es so schreiben, aber test unterstützt es nicht:
if [ $Host == user1 -o $Host == node* ];
then
echo yes
fi
test verwendet = für die String-Gleichheit, was noch wichtiger ist, es unterstützt keine Mustererkennung.
case
/esac
unterstützt den Mustervergleich gut:
case $Host in
user1|node*) echo yes ;;
esac
es hat den zusätzlichen Vorteil, dass es nicht von bash abhängt, die Syntax ist portabel. Aus der Single Unix-Spezifikation The Shell Command Language:
case Word in
[(]pattern1) compound-list;;
[[(]pattern[ | pattern] ... ) compound-list;;] ...
[[(]pattern[ | pattern] ... ) compound-list]
esac
grep
Vergessen Sie die Leistung, dies ist POSIX und sieht besser aus als case
-Lösungen:
mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
echo matches
fi
Erläuterung:
printf '%s'
, um zu verhindern, dass printf
den Backslash-Escape erweitert: Bash-Printf-Literal-Wortfolgegrep -q
verhindert das Echo von Übereinstimmungen mit stdout: So prüfen Sie mit Bash, ob eine Datei eine bestimmte Zeichenfolge enthältgrep -E
aktiviert erweiterte reguläre Ausdrücke, die wir für den ^
benötigenIch habe @ markrushakoffs Antwort angepasst, um es zu einer aufrufbaren Funktion zu machen:
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" == "" ]]
}
Benutze es so:
$ 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
Hier ist eine komplexere Version, die einen bestimmten Standardwert vorsieht:
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* ]]
}
Benutze es so:
$ 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