Überprüfen Sie, ob eine Datei ausführbar ist

78

Ich frage mich, wie ich am einfachsten überprüfen kann, ob ein Programm mit bash ausführbar ist, ohne es auszuführen. Es sollte zumindest prüfen, ob die Datei Ausführungsrechte hat und dieselbe Architektur aufweist (z. B. keine ausführbare Windows-Datei oder eine andere nicht unterstützte Architektur, nicht 64 Bit, wenn das System 32 Bit hat, ...) wie das aktuelle System.

Bob
quelle
Ich würde denken, entweder ls -la [Dateiname] oder stat [Dateiname]
ControlAltDel
Weder ls -la noch stat geben Auskunft über die unterstützte Architektur, was eigentlich der Teil der Frage ist, an der ich am meisten interessiert bin. Ich habe einen Fehler festgestellt, weil keine ausführbare Datei für meine Architektur kompiliert wurde und ich sie erstellen möchte ein Skript, um dies in Zukunft zu vermeiden.
Bob
2
@bob: Haben Sie versucht, die Ausgabe von filerun für diese Dateien zu überprüfen ?
FatalError
@FatalError Wie kann ich die Dateiausgabe analysieren, um zu überprüfen, ob die ausführbare Datei mit meiner Architektur kompatibel ist?
Bob
Überprüfen Sie: Dateitestoperatoren
Ani Menon

Antworten:

110

Schauen Sie sich die verschiedenen Testoperatoren an (dies gilt für den Testbefehl selbst, aber die integrierten BASH- und TCSH-Tests sind mehr oder weniger gleich).

Sie werden feststellen, -x FILEdass FILE existiert und die Berechtigung zum Ausführen (oder Suchen) erteilt wurde .

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- oder CSH-Skript:

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

Um die zu bestimmen Art von Datei es sich handelt, versuchen Sie die Datei - Befehl. Sie können die Ausgabe analysieren, um genau zu sehen, um welchen Dateityp es sich handelt. Word 'o Warnung : Manchmal filewird mehr als eine Zeile zurückgegeben. Folgendes passiert auf meinem 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

Der fileBefehl gibt je nach Betriebssystem unterschiedliche Ausgaben zurück. Das Wort executablewird jedoch in ausführbaren Programmen enthalten sein, und normalerweise wird auch die Architektur angezeigt.

Vergleichen Sie das Obige mit dem, was ich auf meiner Linux-Box bekomme:

$ 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

Und eine Solaris-Box:

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

In allen drei, werden Sie das Wort sehen executableund die Architektur ( x86-64, i386oder SPARCmit 32-bit).


Nachtrag

Vielen Dank, das scheint der richtige Weg zu sein. Bevor ich dies als meine Antwort markiere, können Sie mich bitte anleiten, welche Art von Skript-Shell-Prüfung ich für 'Datei' durchführen müsste (dh welche Art von Analyse), um zu prüfen, ob ich ein Programm ausführen kann? Wenn ein solcher Test im Allgemeinen zu schwierig ist, möchte ich zumindest prüfen, ob es sich um eine ausführbare Linux-Datei oder um osX (Mach-O) handelt.

Auf den ersten Blick könnten Sie in BASH so etwas tun:

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

Grundsätzlich führe ich den Test aus. Wenn dies erfolgreich ist, überprüfe ich die Ausgabe des fileBefehls. Die grep -qMittel drucken keine Ausgabe, sondern verwenden den Exit-Code von grep, um zu sehen, ob ich die Zeichenfolge gefunden habe. Wenn Ihr System nicht benötigt, grep -qkönnen Sie es versuchen grep "regex" > /dev/null 2>&1.

Auch hier kann die Ausgabe des fileBefehls von System zu System variieren. Sie müssen daher überprüfen, ob diese auf Ihrem System funktionieren. Außerdem überprüfe ich das ausführbare Bit. Wenn eine Datei eine binäre ausführbare Datei ist, das ausführbare Bit jedoch nicht aktiviert ist, ist sie nicht ausführbar. Dies ist möglicherweise nicht das, was Sie wollen.

David W.
quelle
hat Bourne Shell [[oder nur [?
Glenn Jackman
2
@glennjackman Bourne-Shell hat nur [einen externen Befehl und keinen eingebauten Shell-Befehl. Es befindet sich normalerweise im /binVerzeichnis. Es ist ein Alias ​​für den testBefehl.
David W.
Vielen Dank, das scheint der richtige Weg zu sein. Bevor ich dies als meine Antwort markiere, können Sie mich bitte anleiten, welche Art von Skript-Shell-Prüfung ich für 'Datei' durchführen müsste (dh welche Art von Analyse), um zu prüfen, ob ich ein Programm ausführen kann? Wenn ein solcher Test im Allgemeinen zu schwierig ist, möchte ich zumindest prüfen, ob es sich um eine ausführbare Linux-Datei oder um osX (Mach-O) handelt.
Bob
@ Bob Siehe den Nachtrag zu meiner Antwort .
David W.
Danke, ich habe es als meine Antwort markiert. Die Idee, die ich hatte, war ganz anders: Ich dachte, ich könnte diese ausführbare Datei mit einer vergleichen, die sich bereits auf dem System befindet, um festzustellen, ob sie dieselbe Architektur haben. Vergleichen Sie es beispielsweise mit der Datei "/ bin / ls". Halten Sie das für eine gute Idee?
Bob
16

Es scheint, dass niemand bemerkt hat, dass der -xOperator die Datei mit dem Verzeichnis nicht unterscheidet.

Um eine ausführbare Datei genau zu überprüfen, können Sie sie verwenden [[ -f SomeFile && -x SomeFile ]]

osexp2003
quelle
5

Außerdem scheint niemand den Operator -x auf Symlinks bemerkt zu haben. Ein Symlink (Kette) zu einer regulären Datei (nicht als ausführbar klassifiziert) besteht den Test nicht.

Dick Guertin
quelle
5

Testen von Dateien, Verzeichnissen und Symlinks

Die hier angegebenen Lösungen schlagen entweder in Verzeichnissen oder in Symlinks (oder in beiden) fehl. Unter Linux können Sie Dateien, Verzeichnisse und Symlinks testen mit:

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

Unter OS X sollten Sie in der Lage sein, Coreutils mit Homebrew zu installieren und zu verwenden grealpath .

Definieren eines isexec Funktion

Sie können der Einfachheit halber eine Funktion definieren:

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

Oder einfach

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

Dann können Sie testen mit:

if `isexec "$file"`; then ... fi
Pyrocrasty
quelle
meinst du nicht return truestatt echo true?
6.
@ Jan6 Ja, danke. Ich habe diese Version wahrscheinlich zum Testen verwendet und vergessen, sie zu ändern.
Pyrocrasty
Außerdem fehlt dem Oneliner ein Semikolon vor der Endklammer (zumindest Bash will das, ]]; }nicht sicher, wie Sie dieses verpasst haben). Und obwohl es die Funktionalität nicht ändert, brauchen Sie nicht einmal die Häkchen in der ifAnweisung :) (I. Vermutlich macht es das Hervorheben anders, kein anderer Unterschied, wenn die Rückgabestatus
stimmen
@ jan6: danke, das habe ich gerade hinzugefügt, als ich die letzte Bearbeitung gemacht habe. Ich habe nicht daran gedacht, Bash einzuchecken (zsh benötigt kein Semikolon).
Pyrocrasty
Auch beim Thema Shell-Unterschiede funktioniert die Verwendung von "return true" in der ersten Version unter zsh nicht richtig (obwohl dies bei bash der Fall ist). Das Ersetzen durch einfach "true" funktioniert jedoch bei beiden.
Pyrocrasty
0

Um zu testen, ob für eine Datei selbst ACL_EXECUTEin einem der Berechtigungssätze (Benutzer, Gruppe, andere) ein Bit gesetzt ist, unabhängig davon, wo sie sich befindet, i. e. Verwenden Sie auch auf einem  tmpfs mit der  Option noexec , stat -c '%A'um die Berechtigungszeichenfolge abzurufen , und überprüfen Sie dann, ob sie mindestens einen einzelnen "x" -Buchstaben enthält:

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

Der rechte Teil des Vergleichs kann geändert werden, um spezifischeren Fällen zu entsprechen, z. B. um *x*x*x*zu prüfen, ob alle Arten von Benutzern die Datei ausführen können sollten, wenn sie auf einem mit der Option exec bereitgestellten Volume abgelegt wird  .

Anton Samsonov
quelle
0

Dies ist möglicherweise nicht so offensichtlich, aber manchmal ist es erforderlich, die ausführbare Datei zu testen, um sie ohne einen externen Shell-Prozess ordnungsgemäß aufzurufen:

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

Unter Linux :

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