【问题标题】:Check if a file is executable检查文件是否可执行
【发布时间】:2012-04-25 16:16:41
【问题描述】:

我想知道在不执行程序的情况下检查程序是否可以使用 bash 执行的最简单方法是什么?它至少应该检查文件是否具有执行权限,并且与当前系统具有相同的体系结构(例如,不是 windows 可执行文件或其他不受支持的体系结构,如果系统是 32 位,则不是 64 位,...)。

【问题讨论】:

  • 我认为是 ls -la [文件名] 或 stat [文件名]
  • ls -la 和 stat 都没有提供有关支持的架构的信息,这实际上是我最感兴趣的问题的一部分。我遇到了一个错误,因为没有为我的可执行文件编译架构,我想创建一个脚本以避免将来出现这种情况。
  • @bob:你试过检查file在这些文件上运行的输出吗?
  • @FatalError 如何解析文件输出以检查可执行文件是否符合我的架构?

标签: bash tcsh


【解决方案1】:

看看各种test 运算符(这是针对测试命令本身的,但内置的 BASH 和 TCSH 测试或多或少相同)。

您会注意到-x FILE 表示文件存在并且已授予执行(或搜索)权限

BASH、Bourne、Ksh、Zsh 脚本

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

TCSH 或 CSH 脚本:

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

要确定文件的类型,请尝试file 命令。您可以解析输出以准确查看它是什么类型的文件。 Word 'o Warning:有时file 会返回不止一行。以下是我的 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

file 命令根据操作系统返回不同的输出。但是executable这个词会出现在可执行程序中,通常架构也会出现。

将上面的内容与我在 Linux 机器上得到的内容进行比较:

$ 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

还有一个 Solaris 盒子:

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

在所有三个中,您都会看到单词 executable 和架构(x86-64i386SPARC32-bit)。


附录

非常感谢,这似乎是要走的路。在我将此标记为我的答案之前,请您指导我必须对“文件”执行什么样的脚本外壳检查(即,什么样的解析)以检查我是否可以执行程序?如果这样的测试很难在一般基础上进行,我至少想检查它是 linux 可执行文件还是 osX (Mach-O)

在我的脑海中,你可以在 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

基本上,我正在运行测试,如果测试成功,我会对file 命令的输出执行 grep。 grep -q 表示不打印任何输出,而是使用 grep 的退出代码查看是否找到该字符串。如果你的系统不接受grep -q,你可以试试grep "regex" > /dev/null 2>&1

同样,file 命令的输出可能因系统而异,因此您必须验证这些是否可以在您的系统上运行。另外,我正在检查可执行位。如果文件是二进制可执行文件,但可执行位未打开,我会说它不可执行。这可能不是你想要的。

【讨论】:

  • Bourne shell 有[[ 还是只有[
  • @glennjackman Bourne shell 只有 [ 这实际上是一个外部命令,而不是 shell 的内置命令。它通常位于/bin 目录中。它是test 命令的别名。
  • 非常感谢,这似乎是要走的路。在我将此标记为我的答案之前,请您指导我必须对“文件”执行什么样的脚本外壳检查(即,什么样的解析)以检查我是否可以执行程序?如果这样的测试很难在一般基础上进行,我至少想检查它是 linux 可执行文件还是 osX (Mach-O)。
  • @bob 请参阅我的answer 的附录。
  • 谢谢,我将其标记为我的答案。我的想法完全不同:我想我可以将这个可执行文件与系统上已经存在的可执行文件进行比较,看看它们是否具有相同的架构。例如,将其与文件“/bin/ls”进行比较。你认为这是个好主意吗?
【解决方案2】:

首先您需要记住,在 Unix 和 Linux 中,一切都是文件,甚至是目录。一个文件有权限作为命令执行,它需要满足3个条件:

  1. 必须是普通文件
  2. 它需要有读取权限
  3. 它需要有执行权限

所以这可以简单地完成:

[ -f "${file}" ] && [ -r "${file}" ] && [ -x "${file}" ]

如果您的文件是指向常规文件的符号链接,则 test 命令将对目标而不是链接名称进行操作。所以上面的命令区分文件是否可以用作命令。因此,无需先将文件传递给 realpathreadlink 或任何这些变体。

如果文件可以在当前操作系统上执行,那就是另一个问题了。上面的一些答案已经指出了一些可能性,所以这里不再赘述。

【讨论】:

    【解决方案3】:

    似乎没有人注意到-x 运算符不会将文件与目录不同。

    所以要精确检查可执行文件,您可以使用 [[ -f SomeFile && -x SomeFile ]]

    【讨论】:

      【解决方案4】:

      测试文件、目录和符号链接

      此处给出的解决方案在目录或符号链接(或两者)上都失败。在 Linux 上,您可以使用以下命令测试文件、目录和符号链接:

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

      在 OS X 上,您应该可以使用 homebrew 安装 coreutils 并使用 grealpath

      定义isexec 函数

      为了方便,你可以定义一个函数:

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

      或者干脆

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

      然后您可以使用以下方法进行测试:

      if `isexec "$file"`; then ... fi
      

      【讨论】:

      • 你的意思是return true而不是echo true吗?
      • @jan6 是的,谢谢。我可能用那个版本来测试,忘记改了。
      • 而且 oneliner 在结束括号之前缺少分号(至少 bash 想要那个,]]; },不知道你是怎么错过那个的)虽然它不会改变功能,但你不会甚至需要if 语句中的刻度:) (我想它使它突出显示不同,如果返回状态正确则没有其他区别)
      • @jan6:谢谢,我刚刚在最后一次编辑时添加了这一点。我没想过要签入 bash(zsh 不需要分号)。
      • 另外,关于 shell 差异的话题,在第一个版本中使用“return true”在 zsh 上不能正常工作(尽管它在 bash 上可以)。不过,用简单的“true”替换它对两者都有效。
      【解决方案5】:

      似乎也没有人注意到符号链接上的 -x 运算符。指向常规文件(未归类为可执行文件)的符号链接(链)未通过测试。

      【讨论】:

        【解决方案6】:

        测试文件本身是否在任何权限集(用户、组、其他人)中设置了ACL_EXECUTE 位,无论它位于何处,即。 e.即使在带有 noexec 选项的 tmpfs 上,也可以使用 stat -c '%A' 获取权限字符串,然后检查它是否至少包含一个“x”字母:

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

        比较的右侧部分可以修改以适应更具体的情况,例如*x*x*x* 以检查是否所有类型的用户都应该能够在将文件放置在安装有 的卷上时执行该文件exec 选项。

        【讨论】:

          【解决方案7】:

          这可能不是那么明显,但有时需要测试可执行文件以在没有外部 shell 进程的情况下正确调用它:

          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
          

          在 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
          

          在 Linux 中

          > tkl_exec_inproc /bin/bash -c 'echo 123'
          123
          > tkl_exec_inproc ./myscript.sh
          123
          > echo $?
          123
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-04-21
            • 2016-07-11
            • 2013-05-04
            • 2013-04-08
            相关资源
            最近更新 更多