Come ottenere un percorso eseguibile dell'applicazione da Terminale

4

In macOS, le applicazioni possono essere lanciate dalla riga di comando con open -a < application name> .

Vorrei sapere se esiste un comando che restituisce l'eseguibile all'interno il pacchetto di applicazioni, quando l'applicazione non è in esecuzione, spero in qualcosa del genere:

awesomeCommand <application name>
/Applications/***/MacOS/Content/application_executable
    
posta Mathieu Westphal 24.08.2018 - 16:15
fonte

2 risposte

8

I would like to know if there is a command that returns the executable within the application bundle

Non esiste un comando di questo tipo, ma ho scritto uno script di shell che esegue esattamente per qualsiasi pacchetto di applicazioni nel file system del disco di avvio .

Utilizza diversi strumenti da riga di comando inclusi in macOS e sfrutta la documentazione di Apple su Avvia servizi , Pacchetti di applicazioni e Core Foundation Keys . Lo script fa quanto segue:

  1. Cerca /Applications per il pacchetto di applicazioni.
  2. Se non può essere trovato in /Applications , esegue una query sul database di Launch Services, considerando solo i pacchetti di applicazioni sul disco di avvio.
  3. Se è stato trovato un pacchetto di applicazioni, ispeziona Info.plist del pacchetto e cerca una chiave denominata CFBundleExecutable che memorizza l'eseguibile (vedi sotto nella sezione delle informazioni di background per ulteriori informazioni su questo). Altrimenti, stampa un messaggio di errore e uscita.
  4. Stampa il percorso dell'eseguibile sullo standard output.

Lo script comprende sia il nome di un'applicazione con o senza la sua estensione, controlla gli argomenti, visualizza un messaggio di utilizzo e una breve descrizione se eseguito senza argomenti e restituisce uno stato di uscita con un messaggio di errore se necessario.

Poiché lo script ricerca /Applications e potrebbe richiedere una query dispendiosa in termini di tempo per avviare i servizi, non è velocissimo (da ~ 1 secondo a diversi secondi), ma era accurato al 100% nei miei test .

Questo è lo script, con spiegazioni su ciò che viene fatto in ogni passaggio:

#!/bin/bash

# https://apple.stackexchange.com/a/334635
# Variables    
app_name="";
app_path_and_name="";
path_to_lsregister="/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/";

# If run without arguments, issue a usage summary and exit
if [[ "$1" == "" ]]; then
    echo "$(basename $0): returns name of bundle applications’s executable file";
    echo "usage: $(basename $0) [application name]"; 
    exit 0;
fi;

# If argument doesn't end with '.app', append it
if [[ "$1" =~ \.app$ ]]; then
    app_name="$1"
else
    app_name="$1.app";
fi;

# Look for the path of the application bundle
# Search /Applicatinos first
app_path_and_name="$(find /Applications -type d -name "$app_name" -maxdepth 5 | grep -m 1 "$app_name")";
# If not found, search the the LaunchServices database (this is the time-consuming task)
test "$app_path_and_name" || app_path_and_name="$($path_to_lsregister/lsregister -dump | grep -v /Volumes | egrep --max-count 1 "/$app_name$" | sed 's:.* \(/.*\)::')"
# Check if Info.plist exists and is readable
if [[ -r "$app_path_and_name/Contents/Info.plist" ]]; then
    # Extract the CFBundleExecutable key that contains the name of the executable and print it to standard output
    echo "$app_path_and_name/MacOS/$(defaults read "$app_path_and_name/Contents/Info.plist" CFBundleExecutable)";
    exit 0;
else
    echo "Application '$1' not found";
    exit 1
fi

Puoi salvare il file (ad esempio pbex per "eseguibile bundle di stampa") e renderlo eseguibile come segue:

chmod a+x pbex

Se preferisci una funzione, usa invece:

function pbex ()
{ 
    # https://apple.stackexchange.com/a/334635
    # Variables
    local app_name="";
    local app_path_and_name="";
    local path_to_lsregister="/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/";

    # If run without arguments, issue a usage summary and exit
    if [[ "$1" == "" ]]; then
        echo "$FUNCNAME: returns name of bundle applications’s executable file";
        echo "usage: $FUNCNAME [application name]"; 
        return 0;
    fi;

    # If argument doesn't end with '.app', append it
    if [[ "$1" =~ \.app$ ]]; then
        app_name="$1"
    else
        app_name="$1.app";
    fi;

    # Look for the path of the application bundle
    # Search /Applicatinos first
    app_path_and_name="$(find /Applications -type d -name "$app_name" -maxdepth 5 | grep -m 1 "$app_name")";
    # If not found, search the LaunchServices database (this is the time-consuming step)
    test "$app_path_and_name" || app_path_and_name="$($path_to_lsregister/lsregister -dump | grep -v /Volumes | egrep --max-count 1 "/$app_name$" | sed 's:.* \(/.*\)::')"
    # Check if Info.plist exists and is readable
    if [[ -r "$app_path_and_name/Contents/Info.plist" ]]; then
        # Extract the CFBundleExecutable key that contains the name of the executable and print it to standard output
        echo "$app_path_and_name/MacOS/$(defaults read "$app_path_and_name/Contents/Info.plist" CFBundleExecutable)";
        return 0;
    else
        echo "Application '$1' not found";
        return 1
    fi
}

Basta aggiungerlo a .bashrc , sorgente:

. .bashrc

per utilizzare la funzione.

Se devi eseguirlo come (piuttosto lungo) "one-liner", usa (sostituisci <app name> con il nome dell'applicazione senza l'estensione .app):

bash -c "app_name=\"<app name>\.app"; app_path_and_name=\"\"; if [[ \"\$app_name\" == \"\" ]]; then exit 2; fi; app_path_and_name=\"\$(find /Applications -type d -name \"\$app_name\" -maxdepth 5 | grep -m 1 \"\$app_name\")\"; test \"\$app_path_and_name\" || app_path_and_name=\"\$(/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep -v /Volumes | egrep --max-count 1 \"/\$app_name\$\" | sed \"s:.* \(/.*\)::\")\"; if [[ -r \"\$app_path_and_name/Contents/Info.plist\" ]]; then echo \"\$app_path_and_name/MacOS/\$(defaults read \"\$app_path_and_name/Contents/Info.plist\" CFBundleExecutable)\"; exit 0; else echo \"Application \"\$app_name\" not found\"; exit 1; fi"

(Scrivi in un commento che il "comando deve essere lanciato da un QProcess"). Potresti fare quanto segue:

process.start("bash", QStringList() << "-c" << "app_name=\"<app name>\.app"; ...");

Vedi link per ulteriori informazioni.)

Esempi:

$ pbex
pbex: returns name of bundle applications’s executable file
usage: pbex [application name]
$ pbex "Microsoft Edge"
Application 'Microsoft Edge' not found
$ pbex Finder
/System/Library/CoreServices/Finder.app/MacOS/Finder
$ pbex "Quick Look Simulator.app"
/System/Library/Frameworks/Quartz.framework/Versions/A/Frameworks/QuickLookUI.framework/Versions/A/Resources/Quick Look Simulator.app/MacOS/Quick Look Simulator
$ pbex "BalTax 2016"
/Applications/BalTax 2016/BalTax 2016.app/MacOS/JavaApplicationStub
$ pbex ColorSync\ Utility
/Applications/Utilities/ColorSync Utility.app/MacOS/ColorSync Utility

INFORMAZIONI DI BASE

La struttura di un pacchetto di app per bundle macOS è ben nota e documentata da Apple.

Secondo La struttura di un pacchetto di applicazioni macOS , la struttura di base di un'app per Mac è:

MyApp.app/
   Contents/
      Info.plist
      MacOS/
      Resources/ 

dove la cartella MacOS " contiene il codice eseguibile autonomo dell'applicazione . In genere, questa directory contiene solo un file binario con il punto di ingresso principale dell'applicazione e il codice collegato in modo statico Tuttavia, in questa directory è possibile inserire anche altri eseguibili standalone (come strumenti da riga di comando). "

Il file Info.plist è necessario affinché il Finder riconosca un pacchetto di applicazioni come tale. Questa lista di proprietà di informazioni filecontains i dati di elenco di proprietà XML che identifica la configurazione del pacchetto. La chiave che ci interessa è CFBundleExecutable , che memorizza " il nome del file eseguibile principale . Questo è il codice che viene eseguito quando l'utente lancia il tuo applicazione ".

    
risposta data 24.08.2018 - 19:02
fonte
2

Non esattamente un singolo comando, ma posso darti i passaggi per ottenere le informazioni. Queste informazioni provengono da Guida alla programmazione del pacchetto .

Devi conoscere la struttura di un'applicazione.

Nella sua directory root ha una directory Contents. In quella directory c'è una directory MacOS che contiene il codice eseguibile autonomo dell'applicazione e un file Info.plist

Info.plist è un file plist formattato che contiene informazioni sull'applicazione incluso il nome del file eseguibile principale. Questo nome è il valore corrispondente alla chiave CFBundleExecutable.

Quindi l'algoritmo per trovare le applicazioni che iniziano l'eseguibile è

  1. Trova l'applicazione
  2. Trova la directory dei contenuti dell'applicazione
  3. Leggi il file Info.plist ottenendo il valore di CFBundleExecutable
  4. l'eseguibile si trova nella directory MacOs di 2 e viene chiamato il risultato di 3.

Nota I passaggi 1 e 3 non sono banali e richiedono chiamate alle librerie di sistema di Apple

    
risposta data 24.08.2018 - 18:26
fonte

Leggi altre domande sui tag