2

I would like to check for (only) python files for those which do not have the #!/usr/bin/env python in the first line. So, I write a bash script that does the following:

#!/bin/bash

#list all of python files

for file in `find . -name "*.py"`
do
        if [ `head -1 $file` != "#!/usr/bin/env python"] then;
                 echo "no match in file $file"
        else then;
                 echo "match!"
        fi
done

However, for some reason I cannot get the if statement correct! I've looked at many questions, but I cannot find one that succinctly describes the issue. Here is the error message:

./run_test.sh: line 9: syntax error near unexpected token `else'
./run_test.sh: line 9: `    else then;'

where am I going awry? Thank you.

4
  • 1
    correct syntax is : if [[ `head -1 $file` != "#!/usr/bin/env python" ]]; then. also delete the then; after else Commented Sep 5, 2015 at 2:05
  • Change ] then; to ]; then. Commented Sep 5, 2015 at 2:11
  • Why is the double brackets ([[ and ]]) necessary? It doesn't work without them - I just checked. Commented Sep 5, 2015 at 3:37
  • Either you need to surround command in double quotes or use [[. If output of head -1 $file is more than one word or null, then it will break [ syntax. Commented Sep 5, 2015 at 5:09

3 Answers 3

2

You can do something like

find . -type f -name '*.py' -exec \
  awk 'NR==1 && /#!\/usr\/bin\/env python/ \
  { print "Match in file " FILENAME; exit } \
  { print "No match in file " FILENAME; exit }' \
{} \;

If you are going to loop over it, don't use a for loop

#!/bin/bash
find . -type f -name '*.py' -print0 | while IFS= read -r -d $'\0' file; do
  if [[ $(head -n1 "$file") == "#!/usr/bin/env python" ]]; then
      echo "Match in file [$file]"
  else
      echo "No match in file [$file]"
  fi
done
Sign up to request clarification or add additional context in comments.

Comments

1

Things to notice:

  1. The [] after your if statement needs correct spacing
  2. The ';' (if you enter a new line is not necessary) goes after the if and not after the then
  3. You added an extra then after the else.

    #!/bin/bash
    
    #list all of python files
    
    for file in `find . -name "*.py"` 
    do
         if [ `head -1 $file` != "#!/usr/bin/env python" ]; 
         then
             echo "no match in file $file"
         else 
             echo "match!"
         fi
    done
    

Comments

-1

can you use -exec option by any chance? I find it easier.

find . -name "*.py" -exec head -1 {} | grep -H '#!/usr/bin/env python' \;

You can control the output using grep options.


edit

Thanks to @chepner - To avoid the pipe being swallowed too early:

-exec sh -c "head -1 {} | grep -H '#!/usr/bin/env python'" \;

7 Comments

I like this since this most definitely seems like a one-off kind of task.
Yeah, I like this....what does the -H option do? I read the man page, but it doesn't make sense to me: ` -H Always print filename headers with output lines.`
oh, it should print the name of the file, before the matching text. I think -lHZ may actually be best for you, giving just zero-terminated filenames.
You can't have a pipeline in the argument to -exec.
-exec sh -c "head -1 {} | grep -H '#!/usr/bin/env python'" \;
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.