4

Shot in the sky: do you have a script that does chmod -x on all executable files in the system that actually cannot be executed (i.e., they mistakenly have x flag)?

(context:
After copying backup files from NTFS into ext4, the files became executable (html, md, txt, etc.). I'd like to make the files non-executable, but only those that are really non-executable. I will likely have to write the script that iterates over all files in the system (smth like for f in ``find /path``; do intelligent_chmod -x $f; done;, where intelligent_chmod has to look into file and identify if it is either ELF or has the first line !#..., etc.)

10

This uses uses find to look for regular files that have the executable bit set. It then tests them with the file command to see if they really are executables or not. If not, we run chmod a-x on them:

find . -type f -executable \( -exec sh -c 'file -b "$1" | grep -q executable' Test {} \; -o -exec chmod a-x {} \; \)

As you can see, this find command has two -exec expressions which are connected with a logical-OR operator.

How it works

  • -type f -executable

    This tells find to look only for regular files that have the executable bit set.

  • \(

    This begins a group.

    By default, find conditions are AND-ed together and AND binds tighter than OR. In this case, we want to bind just the following two -exec commands together with an OR. To do that, we need a group.

  • -exec sh -c 'file -b "$1" | grep -q executable' Test {} \;

    This has the file program examine each file and grep checks to see if the string executable was in the output of file command.

    In the above, Test serves as the program name ($0) for the sh -c script. (For a discussion of $0 and sh -c, see this question.)

    Here is some sample output from the file command:

    $ file -b bash
    ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=0e188133c8cc5187e22eabd27cbcf46f32060fe3, stripped        
    $ file -b which
    POSIX shell script, ASCII text executable
    

    As you can see, file is smart enough to identify as executable not just ELF files but also a wide variety of script files.

  • -o

    This is logical-OR. This means that the command which follows will only be executed if file did not identify the file as an executable.

  • -exec chmod a-x {} \;

    This removes the executable bit.

  • \)

    This tells find that we have reached the end of the grouped commands.

Limitations

As described in man magic, the program file works by examining the strings in a file. Many files have very distinctive strings. An ELF executable, for example, begins with the hex characters 7f 45 4c 46. Jpeg and png graphics have similarly distinct markers. file does not completely parse or analyze a file and, consequently, for some files, however, the magic fails. As Ayrat points out in the comments, file misinterprets the following:

$ cat tmp.py
Now is the time for all good men
to come to the aid of the party.
from xxx import yyy
$ file tmp.py
tmp.py: Python script, ASCII text executable
  • your one liner just solved it! but could you clarify what does _ mean in the command? – Ayrat Aug 10 '16 at 10:53
  • This will give false negatives in some cases e.g. for scripts that don't have shebang but this is the closest you can get..+1.. – heemayl Aug 10 '16 at 11:21
  • @heemayl: How would a script without a shebang be executed? – Williham Totland Aug 10 '16 at 13:58
  • @WillihamTotland Run it as an argument to the interpreter, shell in this case. – heemayl Aug 10 '16 at 14:00
  • 1
    @Ayrat The _ maps to $0 which the shell treats as the script's name. For a discussion on the use of _, see here – John1024 Aug 10 '16 at 19:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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