Vraag String bevat een subtekenreeks in Bash


Ik heb een string in Bash:

string="My string"

Hoe kan ik testen of het een andere reeks bevat?

if [ $string ?? 'foo' ]; then
  echo "It's there!"
fi

Waar ?? is mijn onbekende operator. Gebruik ik echo en grep?

if echo "$string" | grep 'foo'; then
  echo "It's there!"
fi

Dat ziet er een beetje onhandig uit.


1742
2017-10-23 12:37


oorsprong


antwoorden:


Je kunt gebruiken Marcus's antwoord (* jokertekens) ook buiten een case-statement als je dubbele haakjes gebruikt:

string='My long string'
if [[ $string = *"My long"* ]]; then
  echo "It's there!"
fi

Merk op dat spaties in de naaldstring tussen dubbele aanhalingstekens moeten worden geplaatst, en de * wildcards moeten buiten staan.


2487
2017-10-23 12:55



Als u de regex-benadering verkiest:

string='My string';

if [[ $string =~ .*My.* ]]
then
   echo "It's there!"
fi

386
2017-10-23 20:10



Ik ben niet zeker van het gebruik van een if-statement, maar je kunt een soortgelijk effect krijgen met een case-statement:

case "$string" in 
  *foo*)
    # Do stuff
    ;;
esac

239
2017-10-23 12:47



Compatibel antwoord

Omdat er al veel antwoorden zijn met behulp van Bash-specifieke functies, is er een manier om te werken onder slechtere schalen, zoals :

[ -z "${string##*$reqsubstr*}" ]

In de praktijk zou dit kunnen geven:

string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
  if [ -z "${string##*$reqsubstr*}" ] ;then
      echo "String '$string' contain substring: '$reqsubstr'."
    else
      echo "String '$string' don't contain substring: '$reqsubstr'."
    fi
  done

Dit is getest onder , ,  en  (busybox), en het resultaat is altijd:

String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.

In één functie

Zoals gevraagd door @EeroAaltonen is hier een versie van dezelfde demo, getest onder dezelfde shells:

myfunc() {
    reqsubstr="$1"
    shift
    string="$@"
    if [ -z "${string##*$reqsubstr*}" ] ;then
        echo "String '$string' contain substring: '$reqsubstr'.";
      else
        echo "String '$string' don't contain substring: '$reqsubstr'." 
    fi
}

Dan:

$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.

$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.

Merk op: je moet ontsnappen of dubbele offertes en / of dubbele aanhalingstekens invoegen:

$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.

$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.

Eenvoudige functie

Dit is getest onder ,  en natuurlijk :

stringContain() { [ -z "${2##*$1*}" ]; }

Dat is alles Mensen!

Toen nu:

$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes

... Of als de ingediende tekenreeks leeg zou kunnen zijn, zoals aangegeven door @Sjlver, zou de functie worden:

stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }

of zoals gesuggereerd door Commentaar van Adrian Güntervermijden -o switche:

stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ] ;} ; }

Met lege tekenreeksen:

$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no

135
2017-12-08 23:06



Onthoud dat shell-scripting minder een taal is en meer een verzameling commando's. Instinctief denk je dat deze "taal" vereist dat je een if met een [ of a [[. Beide zijn gewoon opdrachten die een exitstatus retourneren die op succes of mislukking wijst (net als elke andere opdracht). Om die reden zou ik gebruiken grep, en niet de [ opdracht.

Gewoon doen:

if grep -q foo <<<"$string"; then
    echo "It's there"
fi

Nu dat je aan het denken bent if als het testen van de exit-status van de volgende opdracht (compleet met puntkomma). Waarom heroverweeg je niet de bron van de string die je aan het testen bent?

## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...

## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...

De -q optie zorgt ervoor dat grep niets uitvoert, omdat we alleen de retourcode willen. <<< laat de shell het volgende woord uitbreiden en gebruik het als de invoer voor het commando, een versie in één regel van de << hier document (ik weet niet zeker of dit standaard is of een bashisme).


110
2017-10-27 14:57



Het geaccepteerde antwoord is het beste, maar aangezien er meer dan één manier is om dit te doen, is hier nog een andere oplossing:

if [ "$string" != "${string/foo/}" ]; then
    echo "It's there!"
fi

${var/search/replace} is $var met het eerste exemplaar van search vervangen door replace, als het wordt gevonden (het verandert niet $var). Als u probeert te vervangen foo door niets, en de snaar is veranderd, dan natuurlijk foo was gevonden.


73
2017-10-23 14:35



Er zijn dus veel nuttige oplossingen voor de vraag - maar welke is het snelst / gebruikt de minste bron?

Herhaalde tests met dit frame:

/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'

TEST elke keer vervangen:

[[ $b =~ $a ]]           2.92user 0.06system 0:02.99elapsed 99%CPU

[ "${b/$a//}" = "$b" ]   3.16user 0.07system 0:03.25elapsed 99%CPU

[[ $b == *$a* ]]         1.85user 0.04system 0:01.90elapsed 99%CPU

case $b in *$a):;;esac   1.80user 0.02system 0:01.83elapsed 99%CPU

doContain $a $b          4.27user 0.11system 0:04.41elapsed 99%CPU

(doContain stond in het antwoord van F. Houri)

En voor gegiechel:

echo $b|grep -q $a       12.68user 30.86system 3:42.40elapsed 19%CPU !ouch!

Dus de eenvoudige substitutiemogelijkheid wint predicaat, of het nu gaat om een ​​uitgebreide test of een case. De behuizing is draagbaar.

Piping tot 100000 greps is voorspelbaar pijnlijk! De oude regel over het gebruik van externe hulpprogramma's zonder noodzaak is waar.


31
2017-08-27 19:42



Dit werkt ook:

if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  printf "Found needle in haystack"
fi

En de negatieve test is:

if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
  echo "Did not find needle in haystack"
fi

Ik veronderstel dat deze stijl een beetje klassieker is - minder afhankelijk van de eigenschappen van de Bash-schaal.

De -- argument is pure POSIX-paranoia, gebruikt om te worden beschermd tegen invoerreeksen die lijken op opties, zoals --abc of -a.

Opmerking: in een korte lus zal deze code zijn veel langzamer dan het gebruik van interne Bash shell-functies, omdat één (of twee) afzonderlijke processen zullen worden gecreëerd en verbonden via leidingen.


22
2017-12-01 15:41



Wat denk je hiervan:

text="   <tag>bmnmn</tag>  "
if [[ "$text" =~ "<tag>" ]]; then
   echo "matched"
else
   echo "not matched"
fi

11
2018-02-09 06:15