标签云

微信群

扫码加入我们

WeChat QR Code

I have a string in Bash:string="My string"How can I test if it contains another string?if [ $string ?? 'foo' ]; thenecho "It's there!"fiWhere ?? is my unknown operator. Do I use echo and grep?if echo "$string" | grep 'foo'; thenecho "It's there!"fiThat looks a bit clumsy.


Hi, if empty strings are false, why do you consider it clumsy? It was the only way that worked for me, despite the proposed solutions.

2019年10月20日55分15秒

You can use the expr command here

2019年10月20日55分15秒

Here's one for posix shells: stackoverflow.com/questions/2829613/…

2019年10月20日55分15秒

Also note that you can reverse the comparison by just switching to != in the test. Thanks for the answer!

2019年10月20日55分15秒

Jonik: You may be missing the shebang or have it as #!/bin/sh. Try #!/bin/bash instead.

2019年10月20日55分15秒

Leave a space between the brackets and the contents.

2019年10月21日55分15秒

You don't need to quote variables inside [[]]. This will work just as well: [[ $string == $needle ]] && echo found

2019年10月20日55分15秒

Orwellophile Careful! You can only omit the double quotes in the first argument to [[. See ideone.com/ZSy1gZ

2019年10月20日55分15秒

Had to replace an egrep regex in a bash script, this worked perfectly!

2019年10月20日55分15秒

If I need space, it not work, how do this?

2019年10月20日55分15秒

The =~ operator already searches the whole string for a match; the .*'s here are extraneous. Also, quotes are generally preferable to backslashes: [[ $string =~ "My s" ]]

2019年10月20日55分15秒

bukzor Quotes stopped working here as of Bash 3.2+: tiswww.case.edu/php/chet/bash/FAQ E14).It's probably best to assign to a variable (using quotes), then compare.Like this: re="My s"; if [[ $string =~ $re ]]

2019年10月20日55分15秒

Test if it does NOT contain a string:if [[ ! "abc" =~ "d" ]] is true.

2019年10月20日55分15秒

This is probably the best solution since it is portable to posix shells. (a.k.a. no bashisms)

2019年10月20日55分15秒

technosaurus I find it rather odd to criticize "bashism" in a questionthat has only bash tag :)

2019年10月20日55分15秒

P.P. It's not so much a criticism as the preference of a more universal solution over a more limited one. Please consider that, years later, people (like me) will stop by to look for this answer and may be pleased to find one that's useful in a wider scope than the original question. As they say in the Open Source world: "choice is good!"

2019年10月20日55分15秒

technosaurus, FWIW [[ $string == *foo* ]] also works in some POSIX compliant sh versions (e.g. /usr/xpg4/bin/sh on Solaris 10) and ksh (>= 88)

2019年10月20日55分15秒

maxschlepzig ...not if there are characters in $IFS such as space, newline, tab or user defined separator... case statement works though without wierd mixed quotation or having to push and pop IFS

2019年10月20日55分15秒

This would be even better, if you can figure out some way to put that to a function.

2019年10月20日55分15秒

EeroAaltonen How do you find my (new added) function?

2019年10月20日55分15秒

I know! find . -name "*" | xargs grep "myfunc" 2> /dev/null

2019年10月20日55分15秒

This is wonderful because it's so compatible. One bug, though: It does not work if the haystack string is empty. The correct version would be string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; }A final thought: does the empty string contain the empty string? The version above things yes (because of the -o -z "$1" part).

2019年10月20日55分15秒

+1. Very good! For me I changed order stringContain() { [ -z "${1##*$2*}" ] && [ -z "$2" -o -n "$1" ]; };"Search where" "Find what". Work in busybox. Accepted answer above don't work in busybox.

2019年10月20日55分15秒

they are called here strings (3.6.7) I believe it is bashism

2019年10月21日55分15秒

one can also use Process Substitution if grep -q foo <(echo somefoothing); then

2019年10月20日55分15秒

Note that echo is unportable, if you're passing a variable, use printf '%s' "$string instead.

2019年10月20日55分15秒

The cost of this is very expensive: doing grep -q foo <<<"$mystring" implie 1 fork and is bashism and echo $mystring | grep -q foo implie 2 forks (one for the pipe and the second for running /path/to/grep)

2019年10月20日55分15秒

BrunoBronosky echo without flags might still have unexpected portability problems if the argument string contains backslash sequences. echo "nope\c" is expected on some platforms to work like echo -e "nope" on some others. printf '%s' "nope" vs printf '%s\n' 'nope\c'

2019年10月20日55分15秒

ephemient's solution above: > ` if [ "$string" != "${string/foo/}" ]; then echo "It's there!" fi` is useful when using BusyBox's shell ash. The accepted solution does not work with BusyBox because some bash's regular expressions are not implemented.

2019年10月20日55分15秒

the inequality of difference. Pretty weird thought! I love it

2019年10月20日55分15秒

unless your string is 'foo' though

2019年10月20日55分15秒

Neat benchmark. Convinced me to use [[ $b == *$a* ]].

2019年10月20日55分15秒

If I'm reading this correctly, case wins with the smallest overall time consumption.You are missing an asterisk after $b in *$a though.I get slightly faster results for [[ $b == *$a* ]] than for case with the bug corrected, but it could depend on other factors too, of course.

2019年10月20日55分15秒

ideone.com/5roEVt has my experiment with some additional bugs fixed and tests for a different scenario (where the string is actually not present in the longer string). Results are largely similar; [[ $b == *$a* ]] is quick and case is almost as quick (and pleasantly POSIX-compatible).

2019年10月20日55分15秒

The OP is clearly tagged with bash.

2019年10月20日55分15秒

...but the OP doesn't say which version of bash; e.g., older bash's (such as solaris frequently has) may not include these newer bash features. (I've run into this exact problem (bash pattern matching not implemented) on solaris w/ bash 2.0)

2019年10月20日55分15秒

echo is unportable, you should be using printf '%s' "$haystack instead.

2019年10月20日55分15秒

Nope, just avoid echo altogether for anything but literal text without escapes that doesn't start with a -. It may work for you, but it's not portable. Even bash's echo will behave differently depending on whether the xpg_echo option is set. P.S.: I forgot to close the double quote in my previous comment.

2019年10月20日55分15秒

kevinarpe I'm not sure, -- is not listed in the POSIX spec for printf, but you should use printf '%s' "$anything" anyway, to avoid issues if $anything contains a % character.

2019年10月20日55分15秒

=~ is for regexp matching, hence too powerful for the OP's purpose.

2019年10月20日55分15秒

expr is one of those swiss-army-knife utilities that can usually do whatever it is you need to do, once you figure out how to do it, but once implemented, you can never remember why or how it's doing what it's doing, so you never touch it again, and hope that it never stops doing what it's doing.

2019年10月20日55分15秒

michael_n and that's wrong with this answer?I don't understand...

2019年10月20日55分15秒

AloisMahdal I never down-voted, I'm just postulating on why downvotes were given. A cautionary comment. I do use expr, on rare occasion, when portability prevents using bash (eg., inconsistent behavior across older versions), tr (inconsistent everywhere) or sed (sometimes too slow). But from personal experience, whenever re-reading these expr-isms, I have to go back to the man page. So, I would just comment that every usage of expr be commented...

2019年10月20日55分15秒

There was a time when all you had was the original Bourne shell. It lacked some commonly required features, so tools like expr and test were implemented to perform them. In this day and age, there are usually better tools, many of them built into any modern shell. I guess test is still hanging in there, but nobody seems to be missing expr.

2019年10月20日55分15秒

I will add that the echo "Couldn't find statement at the end is a nice trick to return 0 exit statuses for these matching commands.

2019年10月20日55分15秒

nicodjimenez you can not target exit status any more with this solution. Exit status is swallowed up by the status messages ...

2019年10月20日55分15秒

That's exactly what I meant... If you don't have || echo "Couldn't find" then you will return an error exit status if there is no match, which you might not want if you're running a CI pipeline for example where you want all commands to return non error exit statuses

2019年10月20日55分15秒

Please add some explanation. Imparting the underlying logic is more important than just giving the code, because it helps the OP and other readers fix this and similar issues themselves

2019年10月20日55分15秒

[[ "$str" == $substr ]] && echo YES || echo NO

2019年10月20日55分15秒

I'm pretty sure the x hack is only required for very old shells.

1970年01月01日00分03秒

echo is unportable, you should be using printf '%s' "$string" instead. I'm editing the answer because the user doesn't appear to exist anymore.

2019年10月20日55分15秒

Is this an answer?

2019年10月20日55分15秒

upvote. why bother to learn how Bash does it when grep, far more powerful, is more than likely going to be available. also extend it a bit further by matching against a list of patterns: grep -q -E 'pattern1|...|patternN'.

2019年10月20日55分15秒