97

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

4

7 回答 7

130

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

您会注意到-x FILEFILE存在并授予执行(或搜索)权限

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 警告:有时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-64i386SPARCwith 32-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命令的输出可能因系统而异,因此您必须验证这些是否可以在您的系统上运行。另外,我正在检查可执行位。如果文件是二进制可执行文件,但可执行位未打开,我会说它不可执行。这可能不是你想要的。

于 2012-04-25T16:27:37.847 回答
23

似乎没有人注意到-x操作员不会将文件与目录不同。

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

于 2016-09-14T11:17:55.410 回答
7

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

此处给出的解决方案在目录或符号链接(或两者)上都失败。在 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
于 2018-04-07T13:20:41.387 回答
5

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

于 2016-12-03T06:04:35.477 回答
1

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

  1. 它需要是一个常规文件
  2. 它需要具有读取权限
  3. 它需要有执行权限

所以这可以通过以下方式简单地完成:

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

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

如果文件可以在当前操作系统上执行,那就是另一个问题了。上面的一些答案已经指出了一些可能性,因此无需在此重复。

于 2021-02-19T11:13:45.653 回答
0

这可能不是那么明显,但有时需要测试可执行文件以在没有外部 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
于 2020-04-04T07:15:19.163 回答
0

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

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

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

于 2020-03-18T11:47:18.130 回答