Проверить, является ли файл исполняемым

Мне интересно, какой самый простой способ проверить, является ли программа исполняемой с помощью bash, не выполняя ее? Он должен, по крайней мере, проверить, имеет ли файл права на выполнение и имеет ли он ту же архитектуру (например, не исполняемый файл Windows или другую неподдерживаемую архитектуру, а не 64-битную, если система 32-битная, ...), что и текущая система.


person bob    schedule 25.04.2012    source источник
comment
Я бы подумал либо ls -la [имя файла], либо stat [имя файла]   -  person ControlAltDel    schedule 25.04.2012
comment
Ни ls -la, ни stat не дают информации о поддерживаемой архитектуре, что на самом деле является частью вопроса, который меня больше всего интересует. Я столкнулся с ошибкой, потому что исполняемый файл не был скомпилирован для моей архитектуры, и я хотел бы создать скрипт, чтобы избежать этого в будущем.   -  person bob    schedule 25.04.2012
comment
@bob: Вы пробовали проверить вывод file для этих файлов?   -  person FatalError    schedule 25.04.2012
comment
@FatalError Как я могу проанализировать вывод файла, чтобы проверить, совместим ли исполняемый файл с моей архитектурой?   -  person bob    schedule 26.04.2012
comment
Проверьте: операторы проверки файлов   -  person Ani Menon    schedule 28.02.2020


Ответы (7)


Взгляните на различные операторы test (это для самой команды 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

И коробка Солярис:

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

Во всех трех вы увидите слово executable и архитектуру (x86-64, i386 или SPARC с 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

По сути, я запускаю тест, затем, если он успешен, я делаю grep на выходе команды file. grep -q означает, что ничего не выводится, а используется код выхода grep, чтобы узнать, нашел ли я строку. Если ваша система не принимает grep -q, вы можете попробовать grep "regex" > /dev/null 2>&1.

Опять же, вывод команды file может варьироваться от системы к системе, поэтому вам придется убедиться, что они будут работать в вашей системе. Кроме того, я проверяю исполняемый бит. Если файл является двоичным исполняемым файлом, но бит исполняемого файла не включен, я скажу, что он не является исполняемым. Это может быть не то, что вы хотите.

person David W.    schedule 25.04.2012
comment
у оболочки Bourne есть [[ или только [? - person glenn jackman; 25.04.2012
comment
Оболочка @glennjackman Bourne имеет только [, которая на самом деле является внешней командой, а не встроенной в оболочку. Обычно он находится в каталоге /bin. Это псевдоним команды test. - person David W.; 26.04.2012
comment
Большое спасибо, кажется, это правильный путь. Прежде чем я отмечу это как свой ответ, не могли бы вы указать мне, какую проверку оболочки сценария мне нужно выполнить (т. Е. Какой анализ) для «файла», чтобы проверить, могу ли я выполнить программу? Если такой тест слишком сложен в общих чертах, я хотел бы, по крайней мере, проверить, является ли это исполняемым файлом Linux или osX (Mach-O). - person bob; 26.04.2012
comment
@bob См. дополнение к моему ответу. - person David W.; 26.04.2012
comment
Спасибо, я отметил это как свой ответ. У меня была совершенно другая идея: я думал, что могу сравнить этот исполняемый файл с тем, который уже есть в системе, чтобы увидеть, имеют ли они одинаковую архитектуру. Например, сравните его с файлом /bin/ls. Ты думаешь, это хорошая идея ? - person bob; 27.04.2012
comment
@bob Это то, что file уже делает. Он использует файл с именем магический файл (обычно /etc/magic, но может варьироваться от системы к системе. См. man file, чтобы найти местонахождение магического файла). Взгляните на волшебный файл, чтобы увидеть, что связано с обнаружением конкретного файла. - person David W.; 30.04.2012
comment
Как проверить, является ли он исполняемым для кого-либо? - person Alper; 24.02.2016

Кажется, никто не заметил, что оператор -x не различает файл с каталогом.

Таким образом, чтобы точно проверить исполняемый файл, вы можете использовать [[ -f SomeFile && -x SomeFile ]]

person osexp2003    schedule 14.09.2016

Тестирование файлов, каталогов и символических ссылок

Приведенные здесь решения не работают ни с каталогами, ни с символическими ссылками (или с обоими). В Linux вы можете тестировать файлы, каталоги и символические ссылки с помощью:

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

В OS X вы сможете установить coreutils с помощью homebrew и использовать 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
person pyrocrasty    schedule 07.04.2018
comment
разве ты не имеешь в виду return true вместо echo true? - person jan6; 26.01.2019
comment
@jan6 Да, спасибо. Вероятно, я использовал эту версию для тестирования и забыл ее изменить. - person pyrocrasty; 27.01.2019
comment
Кроме того, в oneliner отсутствует точка с запятой перед закрывающей скобкой (по крайней мере, bash хочет этого, ]]; }, не знаю, как вы это пропустили). И хотя это не меняет функциональность, вам даже не нужны галочки в выражении if :) (Я предполагаю, что это заставляет его выделяться по-другому, никакой другой разницы, если статусы возврата верны) - person jan6; 02.02.2019
comment
@jan6: спасибо, я только что добавил это, когда делал последнее редактирование. Я не подумал проверить в bash (zsh не требует точки с запятой). - person pyrocrasty; 04.02.2019
comment
Кроме того, что касается различий оболочки, использование return true в первой версии не работает должным образом на zsh (хотя на bash работает). Однако замена его просто истинным работает на обоих. - person pyrocrasty; 04.02.2019

Также кажется, что никто не заметил оператора -x на символических ссылках. Символическая ссылка (цепочка) на обычный файл (не классифицируемый как исполняемый) не проходит тест.

person Dick Guertin    schedule 03.12.2016

Чтобы проверить, установлен ли для самого файла бит ACL_EXECUTE в любом из наборов разрешений (пользователь, группа, другие) независимо от того, где он находится, т.е. е. даже в tmpfs с параметром noexec используйте stat -c '%A', чтобы получить строку разрешения, а затем проверьте, содержит ли она хотя бы одну букву "x":

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

Правая часть сравнения может быть изменена, чтобы соответствовать более конкретным случаям, например, *x*x*x*, чтобы проверить, должны ли все типы пользователей иметь возможность запускать файл, когда он помещен на том, смонтированный с помощью exec. вариант.

person Anton Samsonov    schedule 18.03.2020

Это может быть не так очевидно, но иногда требуется протестировать исполняемый файл, чтобы правильно вызвать его без внешнего процесса оболочки:

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
person Andry    schedule 04.04.2020

Во-первых, вам нужно помнить, что в Unix и Linux все является файлом, даже каталоги. Чтобы файл имел права на выполнение как команду, он должен удовлетворять трем условиям:

  1. Это должен быть обычный файл
  2. Он должен иметь права на чтение
  3. Он должен иметь права на выполнение

Итак, это можно сделать просто с помощью:

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

Если ваш файл является символической ссылкой на обычный файл, тестовая команда будет работать с целью, а не с именем ссылки. Таким образом, приведенная выше команда определяет, можно ли использовать файл в качестве команды или нет. Таким образом, нет необходимости сначала передавать файл realpath или readlink или любому из этих вариантов.

Если файл может быть выполнен на текущей ОС, это другой вопрос. Некоторые ответы выше уже указывали на некоторые возможности для этого, поэтому нет необходимости повторять это здесь.

person kvantour    schedule 19.02.2021