Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to determine if a particular word appears in a sentence using Bourne Shell (sh). For example:

#!/bin/bash
INPUT='Lorem ipsum dolor sit amet.'

if [[ "$INPUT" == *dolor* ]]
then
    echo "So true"
else
    echo "Not true"
fi

This works in bash, but I can't use bash, I need something that works in sh

share|improve this question
    
probably this doesn't work since * is the globbing operator responsible for file name expansion (this way it won't work in bash either)!? Why don't you want to use other unix standard tools (sed, awk, perl...)? –  user1146332 Sep 20 '12 at 13:43
    
Your title was sh, but your script was running by bash. Which one? –  warl0ck Sep 20 '12 at 14:36
    
Is it actually Bourne shell? Not ash or dash? Not bash, ksh or zsh running in sh compatibility mode? What's the actual operating system release you're using/targeting? –  bahamat Sep 20 '12 at 18:22

3 Answers 3

I suspect you meant POSIX shell syntax instead of Bourne shell as the Bourne shell is becoming quite a rare dinosaur these days.

Anyway, the answer is the same in both cases:

case $INPUT in
  *dolor*) echo true;;
  *) echo false;;
esac

The last ;; before esac is not required. The POSIX syntax also allows (*dolor*).

share|improve this answer
    
+1. probably need to quote "$INPUT" in the case statement –  glenn jackman Sep 20 '12 at 14:49
2  
No, it's a rare case where you don't need to quote $INPUT (there can't be word splitting or filename generation there) but it does not harm to quote it. –  Stéphane Chazelas Sep 20 '12 at 18:54
    
I know that's true in bash, but in a POSIX shell? –  glenn jackman Sep 20 '12 at 19:33
    
Well yes, what effect would you expect if it weren't quoted? It can't split into words as there's only one string expected. It will not go away if $INPUT is empty. Quotes are needed in list contexts, or potentially for $* for some shells when in non-list contexts. –  Stéphane Chazelas Sep 20 '12 at 19:40
    
@glennjackman bash is following the POSIX spec: the case statement does not do any word splitting on $INPUT. –  jw013 Sep 20 '12 at 21:08

You can use other tools:

  • grep: if echo "$INPUT" | grep --quiet '\bdolor\b'
share|improve this answer
1  
Note that a system that has a Bourne shell is very unlinkely to have a grep that supports \b (GNUism). The -w flag is slightly more portable, but anyway the OP didn't ask to match whole words. –  Stéphane Chazelas Sep 20 '12 at 13:50
3  
The title says "Find word"; I assumed that was the goal. –  l0b0 Sep 20 '12 at 13:52

In case you want to match whole words portably, first, you need to define how words are delimited. If we go for GNU grep -w's definition, then a word is a sequence of letters, numbers or underscore (and a delimiter would be any character that is not any of those). Unfortunately, the definition of "letter" is locale-dependant. POSIX shells can specify letters (with [[:alpha:]], but I don't know of any variant of the Bourne shell that does. So with a POSIX shell, you could do:

word_delimiter='[![:alnum:]_]'
case +$INPUT+ in
 (*${word_delimiter}dolor${word_delimiter}*) echo true;;
 (*) echo false;;
esac

And in the Bourne shell, you would have to assume US letters:

word_delimiter='[!a-zA-Z0-9_]'
case +$INPUT+ in
  *${word_delimiter}dolor${word_delimiter}*) echo true;;
  *) echo false;;
esac

Other options:

if
  tr -cs '[:alnum:]_' '[\n*]' << EOF | grep -qx dolor
$INPUT
EOF
then
  echo true
else
  echo false
fi

While that syntax is POSIX, if you have to deal with as old a system as one having a Bourne shell, you may have issues with that "tr" syntax as there used to be two main variants of it in the old pre-POSIX days.

share|improve this answer
1  
If you assume US letters, I'd recommend forcing LC_ALL=C for the duration of the script. Otherwise character ranges like [A-Z] are very locale-dependent. –  jw013 Sep 20 '12 at 21:10
    
Well, if the shell supports locales (but here I was adding this part for the Bourne shell which generally doesn't), then it's good because A-Za-z is likely to match letters in the current locale. If the shell doesn't support locales, then well it will only match ASCII a-zA-Z and not other letters in your locale, but that would be the best you can do. Now it's true that LC_ALL=C would guarantee the same behavior in all shells (except those buggy ones where LC_* must be set at the time of teh shell invocation to be effective). –  Stéphane Chazelas Sep 21 '12 at 9:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.