5

I want to find out all scripts with a specific shebang line. Specifically, I want all files that match the following criteria:

  • It's mostly a plain text file (stuffs created by gzexe don't look very friendly)
  • The 1st line contains solely #!/bin/sh or #! /bin/sh (with a space)

I would like to do this with find, sed and grep (file available).
File names are useless, because some scripts don't have extensions or even have wrong extensions. Also a something.sh may have a shebang line of #!/bin/bash which is also not what I wanted.

Besides, sometimes I would come across a file like this:


#!/bin/sh
blah.blah.blah...

The 1st line is empty and the shebang is located at the 2nd line, which is not what I wanted.
I am able to find shebang lines with find|grep but I don't know how to find lines specifically on the 1st line of a file.
Thanks for any help in advance.

1
  • 1
    So do you need to match the #! on the second line, or only the first? Apr 2, 2017 at 5:00

5 Answers 5

5

If you have GNU grep

grep -rIzl '^#![[:blank:]]*/bin/sh' ./
2

I've combined multiple answers into my version:

find -type f -exec \
  sh -c 'head -n1 "$1" | grep -q "^#![[:blank:]]*/bin/sh"' _ {} \; \
  -print
  • Taken from neuron it uses find -type f -exec to get all files and execute an command on it.
  • Taken from user218374 it uses head -n1 to get only the first line and use grep -q to get only the RC.
  • Taken from Costas it uses [[:blank:]]* to handle spaces and tabs.
  • Avoid the echo from neuron and instead use find's -print directive.
0

If you don't care about which line the #!/bin/sh occurs in a file, then you can try:

find -type f -exec bash -c 'grep -r "^#!.*\/bin\/sh" $1 1> /dev/null && echo $1' _ {} \;

0
for f in ./*; do
   [ -f "$f" ] && [ -x "$f" ] &&
      file -b "$f" | grep -wq text &&
         head -n 1 "$f" | grep -qP '^#!\s*/bin/sh' &&
            printf '%s\n' "$f"
done
0

If various types of executables regardless permissions (i.e. +x) or shebang:

find . \
    -type f `# Files only` \
    -exec bash -c \
        $'file -b -- \'{}\' | grep -qP -- \'executable$\'' \; `# Executable` \
    -print; # Print the path if "exec" exits with status 0

If those with shebang only regardless permissions (i.e. +x):

find . \
    -type f `# Files only` \
    -exec bash -c \
        $'head -n 1 -- \'{}\' | grep -qP -- \'^#!.+\'' \; `# With shebang` \
    -print; # Print the path if "exec" exits with status 0

If those with current User executable permission only:

find . \
    -type f `# Files only` \
    -exec $'test -x \'{}\'' `# With current User executable permission` \
    -print; # Print the path if "exec" exits with status 0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .