Check if a file is executable

后端 未结 6 781
粉色の甜心
粉色の甜心 2020-11-27 16:11

I am wondering what\'s the easiest way to check if a program is executable with bash, without executing it ? It should at least check whether the file has execute rights, a

相关标签:
6条回答
  • 2020-11-27 16:49

    To test whether a file itself has ACL_EXECUTE bit set in any of permission sets (user, group, others) regardless of where it resides, i. e. even on a tmpfs with noexec option, use stat -c '%A' to get the permission string and then check if it contains at least a single “x” letter:

    if [[ "$(stat -c '%A' 'my_exec_file')" == *'x'* ]] ; then
        echo 'Has executable permission for someone'
    fi
    

    The right-hand part of comparison may be modified to fit more specific cases, such as *x*x*x* to check whether all kinds of users should be able to execute the file when it is placed on a volume mounted with exec option.

    0 讨论(0)
  • 2020-11-27 16:53

    Testing files, directories and symlinks

    The solutions given here fail on either directories or symlinks (or both). On Linux, you can test files, directories and symlinks with:

    if [[ -f "$file" && -x $(realpath "$file") ]]; then .... fi
    

    On OS X, you should be able to install coreutils with homebrew and use grealpath.

    Defining an isexec function

    You can define a function for convenience:

    isexec() {
        if [[ -f "$1" && -x $(realpath "$1") ]]; then
            true;
        else
            false;
        fi;
    }
    

    Or simply

    isexec() { [[ -f "$1" && -x $(realpath "$1") ]]; }
    

    Then you can test using:

    if `isexec "$file"`; then ... fi
    
    0 讨论(0)
  • 2020-11-27 16:54

    Take a look at the various test operators (this is for the test command itself, but the built-in BASH and TCSH tests are more or less the same).

    You'll notice that -x FILE says FILE exists and execute (or search) permission is granted.

    BASH, Bourne, Ksh, Zsh Script

    if [[ -x "$file" ]]
    then
        echo "File '$file' is executable"
    else
        echo "File '$file' is not executable or found"
    fi
    

    TCSH or CSH Script:

    if ( -x "$file" ) then
        echo "File '$file' is executable"
    else
        echo "File '$file' is not executable or found"
    endif
    

    To determine the type of file it is, try the file command. You can parse the output to see exactly what type of file it is. Word 'o Warning: Sometimes file will return more than one line. Here's what happens on my Mac:

    $ file /bin/ls    
    /bin/ls: Mach-O universal binary with 2 architectures
    /bin/ls (for architecture x86_64):  Mach-O 64-bit executable x86_64
    /bin/ls (for architecture i386):    Mach-O executable i386
    

    The file command returns different output depending upon the OS. However, the word executable will be in executable programs, and usually the architecture will appear too.

    Compare the above to what I get on my Linux box:

    $ file /bin/ls
    /bin/ls: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9, dynamically linked (uses shared libs), stripped
    

    And a Solaris box:

    $ file /bin/ls
    /bin/ls:        ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped
    

    In all three, you'll see the word executable and the architecture (x86-64, i386, or SPARC with 32-bit).


    Addendum

    Thank you very much, that seems the way to go. Before I mark this as my answer, can you please guide me as to what kind of script shell check I would have to perform (ie, what kind of parsing) on 'file' in order to check whether I can execute a program ? If such a test is too difficult to make on a general basis, I would at least like to check whether it's a linux executable or osX (Mach-O)

    Off the top of my head, you could do something like this in BASH:

    if [ -x "$file" ] && file "$file" | grep -q "Mach-O"
    then
        echo "This is an executable Mac file"
    elif [ -x "$file" ] && file "$file" | grep -q "GNU/Linux"
    then
        echo "This is an executable Linux File"
    elif [ -x "$file" ] && file "$file" | grep q "shell script"
    then
        echo "This is an executable Shell Script"
    elif [ -x "$file" ]
    then
        echo "This file is merely marked executable, but what type is a mystery"
    else
        echo "This file isn't even marked as being executable"
    fi
    

    Basically, I'm running the test, then if that is successful, I do a grep on the output of the file command. The grep -q means don't print any output, but use the exit code of grep to see if I found the string. If your system doesn't take grep -q, you can try grep "regex" > /dev/null 2>&1.

    Again, the output of the file command may vary from system to system, so you'll have to verify that these will work on your system. Also, I'm checking the executable bit. If a file is a binary executable, but the executable bit isn't on, I'll say it's not executable. This may not be what you want.

    0 讨论(0)
  • 2020-11-27 16:54

    Seems nobody noticed that -x operator does not differ file with directory.

    So to precisely check an executable file, you may use [[ -f SomeFile && -x SomeFile ]]

    0 讨论(0)
  • 2020-11-27 17:08

    This might be not so obvious, but sometime is required to test the executable to appropriately call it without an external shell process:

    function tkl_is_file_os_exec()
    {
      [[ ! -x "$1" ]] && return 255
    
      local exec_header_bytes
      case "$OSTYPE" in
        cygwin* | msys* | mingw*)
          # CAUTION:
          #   The bash version 3.2+ might require a file path together with the extension,
          #   otherwise will throw the error: `bash: ...: No such file or directory`.
          #   So we make a guess to avoid the error.
          #
          {
            read -r -n 4 exec_header_bytes 2> /dev/null < "$1" ||
            {
              [[ -x "${1%.exe}.exe" ]] && read -r -n 4 exec_header_bytes 2> /dev/null < "${1%.exe}.exe"
            } ||
            {
              [[ -x "${1%.com}.com" ]] && read -r -n 4 exec_header_bytes 2> /dev/null < "${1%.com}.com"
            }
          } &&
          if [[ "${exec_header_bytes:0:3}" == $'MZ\x90' ]]; then
            # $'MZ\x90\00' for bash version 3.2.42+
            # $'MZ\x90\03' for bash version 4.0+
            [[ "${exec_header_bytes:3:1}" == $'\x00' || "${exec_header_bytes:3:1}" == $'\x03' ]] && return 0
          fi
        ;;
        *)
          read -r -n 4 exec_header_bytes < "$1"
          [[ "$exec_header_bytes" == $'\x7fELF' ]] && return 0
        ;;
      esac
    
      return 1
    }
    
    # executes script in the shell process in case of a shell script, otherwise executes as usual
    function tkl_exec_inproc()
    {
      if tkl_is_file_os_exec "$1"; then
        "$@"
      else
        . "$@"
      fi
      return $?
    }
    

    myscript.sh:

    #!/bin/bash
    
    echo 123
    
    return 123
    

    In Cygwin:

    > tkl_exec_inproc /cygdrive/c/Windows/system32/cmd.exe /c 'echo 123'
    123
    > tkl_exec_inproc /cygdrive/c/Windows/system32/chcp.com 65001
    Active code page: 65001
    > tkl_exec_inproc ./myscript.sh
    123
    > echo $?
    123
    

    In Linux:

    > tkl_exec_inproc /bin/bash -c 'echo 123'
    123
    > tkl_exec_inproc ./myscript.sh
    123
    > echo $?
    123
    
    0 讨论(0)
  • 2020-11-27 17:09

    Also seems nobody noticed -x operator on symlinks. A symlink (chain) to a regular file (not classified as executable) fails the test.

    0 讨论(0)
提交回复
热议问题