Existe-t-il un moyen de compléter automatiquement la commande d'ouverture dans le terminal?

16

J'utilise fréquemment la open -a commande dans Terminal pour ouvrir des applications via ssh. Comment puis-je compléter automatiquement le nom d'une application?

daviesgeek
la source
Quel shell utilisez-vous?
Daniel Beck
2
Je suppose qu'un moyen un peu plus rapide serait de taper le chemin complet (venez avec moi pendant un moment ici !!), par exemple open -a /Applications/Textedit.app foo.txt(je suppose que c'est ce que vous essayez de faire). Si vous appuyez sur Tab après le /Aof /Applicationspuis sur Tab à nouveau après le /Teof, /Textedit.appcela devrait compléter automatiquement les deux parties pour vous au fur et à mesure. Pas idéal, je l'avoue, mais peut-être un mais mieux. C'était en utilisant Bash.
binarybob
Vous pouvez également essayer suivant les instructions à la fin de ce post: brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2
Lri
@DanielBeck Bash.
daviesgeek

Réponses:

9
_complete_open() {
        COMPREPLY=()
        local cur="${COMP_WORDS[$COMP_CWORD]}"
        local prev="${COMP_WORDS[COMP_CWORD-1]}"
        [[ "$cur" == -* || "$prev" != '-a' ]] && return
        apps="$(mdfind kMDItemKind==Application -onlyin /Applications -onlyin ~/Applications -onlyin /Developer -onlyin ~/Developer | grep -v '/.*/.*/.*/.*/' | sed -E 's|.*/||g;s|\.app$||g' | uniq)"$'Finder\nArchive Utility\nCharacterPalette\nKeyboardViewer'
        local IFS=$'\n'
        if [[ "${cur:0:1}" = '"' || "${cur:0:1}" = "'" ]]; then
            quote="${cur:0:1}"
            cur="${cur:1}"
        fi
        local found="$(grep -i "^$cur" <<< "$apps")"
        if [[ "$quote" == '"' ]]; then
            found="$(sed "s|^|\"|g;s|$|\"|g" <<< "$found")"
        elif [[ "$quote" == "'" ]]; then
            found="$(sed "s|^|'|g;s|$|'|g" <<< "$found")"
        else
            found="$(sed 's| |\\ |g' <<< "$found")"
        fi
        COMPREPLY=($found)
}

complete -o default -F _complete_open open

Troisième version, qui devrait désormais être à la fois insensible à la casse et fonctionner entre guillemets.

Lri
la source
Je n'ai pas pu faire fonctionner ça DVD Player. Des idées ce qui ne va pas? On dirait un onglet au lieu d'un espace ...
Daniel Beck
@DanielBeck Il manquait IFS=$'\n'. Quoi qu'il en soit, j'ai à nouveau modifié la réponse.
Lri
Cela semble bon. Un +1 en retard pour l' mdfindidée. Beau travail sur l'optimisation et les correctifs. CoreServicessont probablement des préférences personnelles. Quelle en est la raison nospace? S'il n'y a qu'un seul programme, je veux continuer tout de suite avec le filen à ouvrir. Juste une préférence personnelle? Une idée sur le problème de devis restant? AFAICT, c'est la seule chose qui reste pour une bonne solution.
Daniel Beck
@DanielBeck J'ai toujours mis le -adrapeau à la fin, donc je suppose que -o nospacec'est juste une préférence personnelle. Peut - être que nous devrions ping Brett Terpstra ou quelque chose à finir cette nerdfest ...
Lri
Merci beaucoup!! @DanielBeck vous aussi. J'ai choisi la version de Lri à cause de la vitesse. Malheureusement, le vôtre était un peu lent. Merci beaucoup à vous deux! Vous m'avez beaucoup aidé et fait augmenter la vitesse de mon terminal.
daviesgeek
7

Ajoutez les éléments suivants à votre .bash_profileou .bashrcet lancez une nouvelle session:

function _complete_open {
    cur=$2
    COMPREPLY=( );

    [[ "$COMP_WORDS" = "open" ]] || return
    [[ "${COMP_WORDS[ $(( $COMP_CWORD - 1 )) ]}" = "-a" ]] || return

    OLDIFS="$IFS"
    IFS=$'\n'
    local _part="${COMP_WORDS[$COMP_CWORD]}"

    if [[ "${_part:0:1}" = '"' || "${_part:0:1}" = "'" ]] ; then
        COMPREPLY=( $( compgen -W "$( mdfind kMDItemKind==Application | sed -e 's|.*/||g' -e 's|.app$||' | sort -u )" -- $cur ) )
    else
        COMPREPLY=( $( compgen -W "$( mdfind kMDItemKind==Application | sed -e 's|.*/||g' -e 's|.app$||' -e 's| |\\\\ |g' | sort -u )" -- $cur ) )
    fi
    IFS="$OLDIFS"
}

complete -o default -F _complete_open open

Pas besoin d'installer quoi que ce soit. Cela fonctionne avec bashhors de la boîte.


Il n'effectuera la saisie semi-automatique des noms de programme que si l'option précédente l'est -aet affiche le comportement par défaut, par exemple, retourne une liste de tous les fichiers du répertoire en cours ou complète le préfixe du chemin en cours.

Les résultats sont générés à partir de system_profiler SPApplicationsDataType, ce qui est le moyen le plus simple d'obtenir toutes les applications qui peuvent être lancées de cette façon sur votre système comme ça. La liste est traitée pour renvoyer uniquement les noms de programme, qui peuvent contenir des espaces et peuvent être différents des noms de bundle (même en ignorant le .appsuffixe)

Utilisation: Tapez open -a, suivi d'un espace, puis appuyez sur Tabou Esc(deux fois sur mon système, je ne sais pas s'il est partout).

Exemple montrant toutes les applications d'assistance pour mon scanner:

$ open -a Scan
Scan to E-mail          Scan to Excel           Scan to Folder          Scan to Print           Scan to Searchable PDF  Scan to Word            ScanSnap Manager

Inconvénients et problèmes de cette solution:

  • Il y a des tonnes de programmes sur votre système que vous ne connaissez peut-être pas, comme tout le reste /System/Library/CoreServices. Vous ne voudrez peut-être pas tous les énumérer. OTOH, c'est vraiment facile à voir et à lancer par exemple CharacterPaletteou de KeyboardViewercette façon. * Configurez les mdfindappels de manière appropriée avec l' -onlyinargument.

  • C'est un peu lent, à cause de system_profiler SPApplicationsDataType. Vous devrez peut-être attendre une ou deux secondes avant que la fin ne s'affiche. Utilise maintenant mdfindpour obtenir rapidement les programmes. Merci @Lri

  • Il peut gérer les espaces dans les noms des applications et les guillemets inclus dans les programmes, mais c'est plutôt hacky. Il requiert que la citation soit le premier caractère: Bien qu'il Scan" to "Psoit valide dans bash, ce programme ne le détectera pas. La complétion ne fonctionne pas non plus après un espace échappé (par exemple Scan\ to), utilisez des guillemets dans de tels cas ( "Scan to). Prise en charge des espaces évadés est seulement bon pour terminer DVDà DVD\ Player.

Daniel Beck
la source
Ce ne serait pas mdfind 'kMDItemKind==Application'plus rapide? Si completion-ignore-caseest activé, grep devrait également ignorer la casse.
Lri
@Lri Tu as raison. Impossible de trouver un cas où ces résultats auraient fait une différence.
Daniel Beck
3

Autocompletion programmable à la rescousse! Besoin de beaucoup de copies depuis la page d'accueil de Bash Completion , ce qui vaut quand même l'installation pour beaucoup de magie de complétion automatique. Si vous le faites, vous n'aurez besoin que de la dernière fonction ( _open) et de la commande d'initialisation ci-dessous.

Ajoutez ce qui suit à .bashrc:

# taken from http://bash-completion.alioth.debian.org/

_compopt_o_filenames()
{
    # We test for compopt availability first because directly invoking it on
    # bash < 4 at this point may cause terminal echo to be turned off for some
    # reason, see https://bugzilla.redhat.com/653669 for more info.
    type compopt &>/dev/null && compopt -o filenames 2>/dev/null || \
        compgen -f /non-existing-dir/ >/dev/null
}

_tilde() {
    local result=0
    # Does $1 start with tilde (~) and doesn't contain slash (/)?
    if [[ ${1:0:1} == "~" && $1 == ${1//\/} ]]; then
        _compopt_o_filenames
        # Try generate username completions
        COMPREPLY=( $( compgen -P '~' -u "${1#\~}" ) )
        result=${#COMPREPLY[@]}
    fi
    return $result
}

_quote_readline_by_ref()
{
    if [[ ${1:0:1} == "'" ]]; then
        if [[ ${BASH_VERSINFO[0]} -ge 4 ]]; then
            # Leave out first character
            printf -v $2 %s "${1:1}"
        else
            # Quote word, leaving out first character
            printf -v $2 %q "${1:1}"
            # Double-quote word (bash-3)
            printf -v $2 %q ${!2}
        fi
    elif [[ ${BASH_VERSINFO[0]} -le 3 && ${1:0:1} == '"' ]]; then
        printf -v $2 %q "${1:1}"
    else
        printf -v $2 %q "$1"
    fi

    # If result becomes quoted like this: $'string', re-evaluate in order to
    # drop the additional quoting.  See also: http://www.mail-archive.com/
    # [email protected]/msg01942.html
    [[ ${!2:0:1} == '$' ]] && eval $2=${!2}
} # _quote_readline_by_ref()

_filedir()
{
    local i IFS=$'\n' xspec

    _tilde "$cur" || return 0

    local -a toks
    local quoted tmp

    _quote_readline_by_ref "$cur" quoted
    toks=( ${toks[@]-} $(
        compgen -d -- "$quoted" | {
            while read -r tmp; do
                printf '%s\n' $tmp
            done
        }
    ))

    if [[ "$1" != -d ]]; then
        # Munge xspec to contain uppercase version too
        [[ ${BASH_VERSINFO[0]} -ge 4 ]] && \
            xspec=${1:+"!*.@($1|${1^^})"} || \
            xspec=${1:+"!*.@($1|$(printf %s $1 | tr '[:lower:]' '[:upper:]'))"}
        toks=( ${toks[@]-} $( compgen -f -X "$xspec" -- $quoted) )
    fi
    [ ${#toks[@]} -ne 0 ] && _compopt_o_filenames

    COMPREPLY=( "${COMPREPLY[@]}" "${toks[@]}" )
} # _filedir()

# only the following is needed if bash-autocompletion is already installed
_open ()
{
    local cur;

    cur=$2;

    COMPREPLY=();
    if [ $COMP_CWORD -eq 2 ]; then
        COMPREPLY=($(compgen -W "$(/bin/ls /Applications)" -- $cur ));
        return 0
    fi

    _filedir
}

complete -F _open open
nohillside
la source
J'ai donc suivi les instructions d'installation et ajouté le code à .bashrc. Maintenant, comment puis-je le compléter automatiquement? Que dois-je pousser pour la saisie semi-automatique? (Désolé, je ne peux pas lire le code)
daviesgeek
1
Ne gère pas les noms de programme avec des espaces (comme DVD Player.app). Répertorie également les répertoires /Applications(comme iWork 09, comme entrées distinctes iWorket 09), mais pas les programmes qui y sont contenus.
Daniel Beck
1

Ceci est activé par défaut avec le shell Zsh , tant que vous avez activé l'achèvement, bien sûr. Zsh est inclus dans OS X.

Tout ce que vous avez à faire est de mettre autoload -Uz compinit; compinitdans votre ~ / .zshrc, ou d'activer l'achèvement via le premier menu de configuration d'exécution.

Zsh est en fait principalement un surensemble de Bash, vous ne devriez donc pas avoir à apprendre quelque chose de nouveau. Même vos scripts fonctionneront probablement!

SilverWolf - Rétablir Monica
la source