narf
narf

Reputation: 5

Escaping Shebang in grep

in a shell script, i'm trying to find out if another file is a shell script. i'm doing that by grepping the shebang line. but my grep statement doesn't work:

if [[ $($(cat $file) | grep '^#! /bin' | wc -l) -gt 0 ]]
then 
echo 'file is a script!'
else 
echo "no script"
fi

i always get the error "bash: #!: command not found". i tried several things to escape the shebang but that didn't work.

maybe you can help me with that? :)

cheers, narf

Upvotes: 0

Views: 756

Answers (2)

fencekicker
fencekicker

Reputation: 850

I had a similar problem, it seems that the '!' needs to be escaped. There's also en unnecessary extra space after '!' in your script. Also, I'm not sure why you're trying to wrap the cat in $(), it works without it (and at least for me, it doesn't work with it):

if [[ $(cat $file | grep '^#\!/bin' | wc -l) -gt 0 ]]; then 
    echo 'file is a script!'; 
else  
    echo "no script"; 
fi

Also, I think grep -q is a good suggestion, it makes the script more compact.

Upvotes: 0

Tom Fenech
Tom Fenech

Reputation: 74685

I would suggest that you change your condition to this:

if grep -q '^#! */bin' "$file"

The -q option to grep is useful in this case as it tells grep to produce no output, exiting successfully if the pattern is matched. This can be used with if directly; there's no need to wrap everything in a test [[ (and especially no need for a useless use of cat).

I also modified your pattern slightly so that the space between #! and /bin is optional.

It's worth noting that this will produce false positives in cases where the match is on a different line of the file, or when another shebang is used. You could work around the first issue by piping head -n 1 to grep, so that only the first line would be checked:

if head -n 1 "$file" | grep -q '^#! */bin'

If you are searching for a known list of shebangs, e.g. /bin/sh and /bin/bash, you could change the pattern to something like ^#! */bin/\(sh\|bash\).

Upvotes: 3

Related Questions