开发者

Trouble nesting expressions in UNIX

I have the following UNIX statement:

#!/bin/bash
$x=$((grep ^'[a-z]' $1 | wc -l))
echo "$x"

However, I'm getting an error message relating to a missing operand whenever I try to run the script. Is there any way to assign a variable a value like so in UNIX?

EDIT:

Well, it became clear to me that grep cannot seem to examine single words, which is what I originally intended to do. Is there a UNIX command that anyone can point me to that deals with searching for a pattern in a word? I'm trying to make some unix code that can tell if a word passed to a script starts with a number. What UNIX call would be the most helpf开发者_如何学Goul?


I believe your remaining problem is that $( ... ) and $(( ... )) are two very different things. The former does command substitution, which is what you want. The latter does arithmetic. Try this:

#! /bin/sh

x=$(grep -c '^[a-z]' "$1")
echo "$x"

I also don't know why you had the caret outside the single quotes; that could cause problems with some shells (where caret either does history expansion or is an alias for |), I think bash is not one of those shells but there's no reason to tempt fate.

Obligatory tangential advice: When expanding shell variables, ALWAYS put them inside double quotes, unless you specifically need word splitting to happen. (This is why I changed $1 to "$1". Without that change, your script would break if you gave it a file with a space in its name.)

EDIT: Now you say you want to know if a word passed to a script starts with a number. By "passed to a script" I am going to assume you mean like this:

./script WORD

The easiest way to do that does not involve grep or command substitution at all:

#! /bin/sh

case "$1" in
    [0-9]*)  
        echo "Starts with a number"
    ;;
    *)
        echo "Doesn't start with a number"
    ;;
esac

Yes, the "case" syntax is gratuitously different from everything else in shell; if you want an internally consistent language, Python is waiting for you thataway. The patterns you put before each open paren are globs, not regexes. If you need a regex, you have to do something more complicated, e.g.

#! /bin/sh

if [ $(expr "$1" : '[0-9]\{3,5\}x') -gt 0 ]; then
    echo "Starts with a three-to-five digit number followed by an x"
fi

Some people say that it is unnecessary to put quotes around the variable expansion that goes between case and in. They are technically correct but should be ignored anyway, because that's one too many warts to remember. Other people say that you can put an open parenthesis before each glob and then your editor will not get grumpy about the mismatched parentheses. I approve of editor non-grumpiness, but I don't know how portable that variation is.


You don't put $ in front of the variable being assigned:

> $x=$(echo -en "1\n2\n3" | grep 3)
bash: =3: command not found
> x=$(echo -en "1\n2\n3" | grep 3)
> echo $x
3

When you write $x before $x exists, it seems to be expanded to nothing; this is why the first line is fully evaluated to just =3.


Zack has the right approach using case. bash has more pattern matching operators:

shopt -s extglob

var="foobar"
if [[ "$var" == @([a-z]*) ]]; then
    echo "var starts with a letter"
fi

In the bash man page, read about [[ under "Compound Commands", and the "Pattern Matching" section.


Instead of wc you can use grep -c.


This should work ok

#!/bin/bash
x=$(grep ^'[a-z]' $1 | wc -l)
echo "$x"

Note that $ is not needed when assigning to variables and the extra () is not needed as well.


x=$(grep '^[a-z]' "$1" | wc -l)

or just one awk command

x=$(awk '/^[a-z]/{c++}END{print c}')
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜