Перевірте, чи файл виконуваний


83

Мені цікаво, який найпростіший спосіб перевірити, чи виконується програма за допомогою bash, не виконуючи її? Він повинен принаймні перевірити, чи має файл права на виконання та чи має він таку ж архітектуру (наприклад, не виконуваний файл Windows чи іншу непідтримувану архітектуру, а не 64 біти, якщо система 32 біти, ...) як поточна система.


Думаю, або ls -la [ім'я файлу], або стати [ім'я файлу]
ControlAltDel

1
Ні ls -la, ні stat не надають інформації про підтримувану архітектуру, що насправді є частиною питання, яке мене найбільше цікавить. Я зіткнувся з помилкою, оскільки виконуваний файл не був скомпільований для моєї архітектури, і я хотів би створити сценарій, щоб уникнути цього в майбутньому.
боб

2
@bob: Ви пробували перевірити вихідні дані fileзапуску цих файлів?
FatalError

1
@FatalError Як я міг проаналізувати вихідний файл, щоб перевірити, чи виконуваний файл відповідає моїй архітектурі?
боб

Відповіді:


115

Погляньте на різні оператори тестування (це стосується самої команди тестування, але вбудовані тести BASH і TCSH більш-менш однакові).

Ви помітите , що -x FILEговорить 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 Script:

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-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команди можуть відрізнятися залежно від системи, тому вам доведеться перевірити, чи вони будуть працювати у вашій системі. Крім того, я перевіряю виконуваний біт. Якщо файл є двійковим виконуваним файлом, але виконуваний біт не ввімкнено, я скажу, що він не є виконуваним. Це може бути не те, що ти хочеш.


є оболонка Борна [[чи просто [?
glenn jackman

2
@glennjackman Bourne має лише оболонку, [яка насправді є зовнішньою командою, а не вбудованою оболонкою. Зазвичай він знаходиться в /binкаталозі. Це псевдонім testкоманди.
Девід В.

Щиро дякую, це, здається, шлях. Перш ніж я позначу це як свою відповідь, чи можете ви, будь-ласка, навести мене щодо того, який тип перевірки оболонки скрипта я повинен був би виконати (тобто, який синтаксичний розбір) для 'файлу', щоб перевірити, чи можу я виконати програму? Якщо такий тест занадто важко зробити на загальних підставах, я хотів би хоча б перевірити, чи це виконуваний файл Linux, або osX (Mach-O).
боб

@bob Див. додаток до моєї відповіді .
Девід В.

Дякую, я позначив це як свою відповідь. Ідея у мене була зовсім інша: я думав, що можу порівняти цей виконуваний файл із таким, який уже є в системі, щоб перевірити, чи вони однакової архітектури. Наприклад, порівняйте його з файлом "/ bin / ls". Чи вважаєте ви, що це гарна ідея?
боб

17

Здається, ніхто не помічав, що -xоператор не відрізняє файл із каталогом.

Отже, щоб точно перевірити виконуваний файл, ви можете використовувати [[ -f SomeFile && -x SomeFile ]]


6

Тестування файлів, каталогів та символьних посилань

Наведені тут рішення не спрацьовують ні в каталогах, ні в символьних посиланнях (або в обох). У Linux ви можете тестувати файли, каталоги та символьні посилання за допомогою:

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

В OS X ви повинні мати можливість встановлювати 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?
січень6,

@ jan6 Так, дякую. Можливо, я використовував цю версію для тестування і забув змінити її.
пірократія

Крім того, у строці oneliner бракує крапки з комою перед кінцевою дужкою (принаймні, bash цього хоче ]]; }, не впевнений, як ви її пропустили). І хоча це не змінює функціональність, вам навіть не потрібні галочки у ifзаяві :) (I думаю, це робить його підсвічуванням різним, ніякої іншої різниці немає, якщо статуси повернення правильні)
січень 6,

@ jan6: дякую, я щойно додав, що коли робив останнє редагування. Я не думав перевіряти bash (zsh не вимагає крапки з комою).
пірократія

Крім того, на тему відмінностей оболонки використання "return true" у першій версії не працює належним чином на zsh (хоча працює на bash). Заміна його просто "справжнім" працює на обох.
пірократія

5

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


0

Щоб перевірити, чи має сам файл ACL_EXECUTEбіт у будь-якому з наборів дозволів (користувач, група та інші), незалежно від того, де він знаходиться, тобто. e. навіть на  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 .


0

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

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.