W bash, Jak mogę sprawdzić, czy ciąg zaczyna się od jakiejś wartości?

Chciałbym sprawdzić, czy łańcuch zaczyna się od "node" np. "node001". Coś jak

if [ $HOST == user* ]  
  then  
  echo yes  
fi

Jak mogę to zrobić poprawnie?


Muszę jeszcze połączyć wyrażenia, aby sprawdzić, czy HOST jest albo "user1", albo zaczyna się od"node"

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

> > > -bash: [: too many arguments

Jak to zrobić poprawnie?

Author: the Tin Man, 2010-01-31

11 answers

Ten fragment w Advanced Bash Scripting Guide mówi:

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

Więc miałeś prawie poprawnie; potrzebowałeś podwójnych nawiasów, a nie pojedynczych nawiasów.


Jeśli chodzi o twoje drugie pytanie, możesz napisać je w ten sposób:
HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

Które będą echo

yes1
yes2

Składnia Basha if jest trudna do przyzwyczajenia (IMO).

 744
Author: Mark Rushakoff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-26 10:17:11

Jeśli używasz najnowszej wersji bash (v3+) sugeruj operator porównywania regex bash =~, tzn.

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

Aby dopasować this or that w regex use |, tzn.

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

Uwaga-jest to 'właściwa' składnia wyrażenia regularnego.

  • user* oznacza use i zero-lub-więcej wystąpień r, więc use i userrrr będą pasować.
  • user.* oznacza user i zero-lub-więcej wystąpień dowolnego znaku, więc user1, userX pasuje.
  • ^user.* oznacza dopasowanie wzorca user.* na początku $HOST.

Jeśli nie znasz składni wyrażeń regularnych, spróbuj odwołać się do tego zasobu.

Uwaga-lepiej jest zadawać każde nowe pytanie jako nowe pytanie, czyni stackoverflow bardziej uporządkowanym i użytecznym. Zawsze możesz podać link do poprzedniego pytania w celach informacyjnych.

 145
Author: brabster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-09 12:26:37

Zawsze staram się trzymać POSIX sh zamiast używać rozszerzeń bash, ponieważ jednym z głównych punktów skryptów jest przenośność. (Oprócz łączenia programów, a nie ich zastępowania)

W sh, jest łatwy sposób, aby sprawdzić warunek "is-prefix".

case $HOST in node*)
    your code here
esac

Biorąc pod uwagę, jak stary, arcane i crufty sh jest (a bash nie jest lekarstwem: jest bardziej skomplikowany, mniej spójny i mniej przenośny), chciałbym zwrócić uwagę na bardzo ładny aspekt funkcjonalny: podczas gdy niektóre składnie elementy takie jak case są wbudowane, powstałe konstrukcje nie różnią się od innych zadań. Można je składać w ten sam sposób:

if case $HOST in node*) true;; *) false;; esac; then
    your code here
fi

Lub nawet krótszy

if case $HOST in node*) ;; *) false;; esac; then
    your code here
fi

Lub nawet krótszy (aby przedstawić ! jako element języka - ale teraz jest to zły styl)

if ! case $HOST in node*) false;; esac; then
    your code here
fi

Jeśli lubisz być jawny, Zbuduj swój własny element języka:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Czy to nie całkiem miłe?
if beginswith node "$HOST"; then
    your code here
fi

A ponieważ SH to w zasadzie tylko jobs i string-list (i procesy wewnętrzne, z których składają się zadania), możemy teraz nawet wykonać lekkie Programowanie funkcyjne: {]}

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
To jest eleganckie. Nie żebym opowiadał się za używaniem sh do czegokolwiek poważnego . łamie się zbyt szybko na realnych wymaganiach (bez lambda, więc trzeba używać stringów. Ale zagnieżdżanie wywołań funkcji z łańcuchami nie jest możliwe, rury nie są możliwe...)
 83
Author: Jo So,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-10 19:08:02

Możesz wybrać tylko część łańcucha, którą chcesz sprawdzić:

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

Do pytania uzupełniającego możesz użyć lub:

if [[ $HOST == user1 || $HOST == node* ]]
 56
Author: martin clayton,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-31 16:53:46

Wolę inne metody już zamieszczone, ale niektórzy lubią używać:

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

Edit:

Dodałem Twoich zastępców do powyższej wypowiedzi

W edytowanej wersji masz za dużo nawiasów. Powinno to wyglądać tak:

if [[ $HOST == user1 || $HOST == node* ]];
 53
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-31 17:43:20

Ponieważ # ma znaczenie w bashu, doszedłem do następującego rozwiązania.
Poza tym wolę pakować struny z "" do pokonywania spacji itp.

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "skip comment line"
fi
 26
Author: ozma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-01 09:11:35

Chociaż większość odpowiedzi tutaj jest całkiem poprawna, wiele z nich zawiera niepotrzebne bashismsy. rozszerzenie parametru POSIX daje Ci wszystko, czego potrzebujesz:

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

I

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

${var#expr} usuwa najmniejszy przedrostek pasujący do expr z ${var} i zwraca go. Stąd Jeśli ${host} nie zaczyna się od user (node), ${host#user} (${host#node}) jest tym samym co ${host}.

expr pozwala fnmatch() wildcards, więc ${host#node??} i przyjaciele również działają.

 23
Author: dhke,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-06 13:02:47

@OP, do obu pytań możesz użyć case / esac

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac
Pytanie drugie]}
case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac

Lub Bash 4.0

case "$HOST" in
 user) ;& 
 node*) echo "ok";; 
esac
 8
Author: ghostdog74,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-01 13:48:59
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi
Nie działa, ponieważ wszystkie [, [[ i test rozpoznać tę samą gramatykę nieekursywną. patrz sekcja wyrażenia warunkowe na stronie podręcznika bash.

Na marginesie, SUSv3 mówi

Wywołanie warunkowe Kornshella (podwójny nawias [[]]) został usunięty z opisu języka poleceń powłoki we wczesnej propozycji. Pojawiły się zastrzeżenia, że prawdziwym problemem jest niewłaściwe wykorzystanie testu dowództwo ([), a umieszczenie go w powłoce to zły sposób na rozwiązanie problemu. Zamiast tego, Odpowiednia dokumentacja i nowe słowo zarezerwowane powłoki (!) są wystarczające.

Testy wymagające wielu operacji test mogą być wykonywane na poziomie powłoki przy użyciu pojedynczych wywołań polecenia test i logicali powłoki, zamiast używać podatnego na błędy znacznika -o z test.

Trzeba by to tak napisać, ale test nie obsługuje:

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

test zastosowania = dla równości ciągów, co ważniejsze, nie obsługuje dopasowania wzorców.

case / esac ma dobre wsparcie dla dopasowania wzorca:

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

Ma dodatkową zaletę, że nie zależy od Basha, składnia jest przenośna. z pojedynczej specyfikacji Uniksa, język poleceń powłoki:

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac
 6
Author: just somebody,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-01 15:33:58

Dodanie trochę więcej szczegółów składni do odpowiedzi Mark Rushakoff najwyższej rangi.

Wyrażenie

$HOST == node*

Można również zapisać jako

$HOST == "node"*

Efekt jest taki sam. Upewnij się tylko, że symbol wieloznaczny znajduje się poza cytowanym tekstem. Jeśli symbol wieloznaczny jest wewnątrz cudzysłowów, będzie on interpretowany dosłownie (tzn. nie jako symbol wieloznaczny).

 1
Author: MrPotatoHead,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-06 05:15:00

Kolejna rzecz, którą możesz zrobić to cat out what you are echoing and pipe with inline cut -c 1-1

 -5
Author: Richard Tang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-28 00:06:28