Existe uma maneira de concluir automaticamente o comando aberto no Terminal?


16

Eu freqüentemente uso o open -a comando no Terminal para abrir aplicativos via ssh. Como faço para concluir automaticamente o nome de um aplicativo?


Qual shell você está usando?
Daniel Beck

2
Eu acho que uma maneira marginalmente mais rápida seria digitar o caminho completo (basta ir comigo por um tempo aqui !!), por exemplo open -a /Applications/Textedit.app foo.txt(presumo que seja isso que você está tentando fazer). Se você pressionar Tab após o /Ade /Applicationse depois Tab novamente após o /Tede /Textedit.app, isso deve preencher automaticamente as duas partes para você à medida que avança. Não é o ideal, admito, mas talvez seja um pouco melhor. Isso estava usando o Bash.
Binarybob

Você também pode tentar seguir as instruções no final deste post: brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2 #
Lri

@DanielBeck Bash.
21412 daviesgeek

Respostas:


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

Terceira versão, que agora deve diferenciar maiúsculas de minúsculas e funcionar entre aspas.


Não consegui fazer isso funcionar DVD Player. Alguma idéia do que está errado? Parece um guia, em vez de um espaço ...
Daniel Beck

@DanielBeck Estava faltando IFS=$'\n'. Enfim, editei a resposta novamente.
Lri

Parece bom. Um +1 atrasado para a mdfindideia. Bom trabalho na otimização e correções. CoreServicesprovavelmente são preferências pessoais. Qual o motivo disso nospace? Se houver apenas 1 programa, desejo continuar imediatamente com o filen para abrir. Apenas preferência pessoal? Alguma idéia sobre o restante da citação? AFAICT, essa é a única coisa que resta para uma solução adequada.
9117 Daniel Beck

@DanielBeck Eu sempre coloco a -abandeira no final, então acho que -o nospaceé apenas uma preferência pessoal. Talvez devêssemos fazer ping Brett Terpstra ou algo para terminar este Nerdfest ...
Lri

Muito obrigado!! @DanielBeck você também. Eu escolhi a versão de Lri por causa da velocidade. Infelizmente, o seu foi um pouco lento. Muito obrigado a vocês dois! Você me ajudou muito e fez a velocidade do meu Terminal aumentar.
daviesgeek

7

Adicione o seguinte ao seu .bash_profileou .bashrce inicie uma nova sessão:

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

Não há necessidade de instalar nada. Isso funciona com bashpronto uso.


Ele só completará automaticamente os nomes de programas se a opção anterior for -ae mostrar o comportamento padrão; por exemplo, retorne uma lista de todos os arquivos no diretório atual ou complete o prefixo do caminho atual.

Os resultados são gerados system_profiler SPApplicationsDataType, o que é a maneira mais fácil de obter todos os aplicativos que podem ser iniciados dessa maneira em seu sistema dessa maneira. A lista é processada para retornar apenas os nomes dos programas, que podem conter espaços e podem ser diferentes dos nomes dos pacotes configuráveis ​​(mesmo ao ignorar o .appsufixo)

Uso: Digite open -a, seguido por um espaço, seguido de pressionar Tabou Esc(duas vezes no meu sistema, não tenho certeza se está em todo lugar).

Exemplo mostrando todos os aplicativos auxiliares do meu 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

Desvantagens e problemas desta solução:

  • Existem muitos programas em seu sistema que você talvez não saiba, como tudo /System/Library/CoreServices. Você pode não querer listar todos eles. OTOH, é realmente fácil ver e iniciar, por exemplo, CharacterPaletteou KeyboardViewerdesta maneira. * Configure as mdfindchamadas adequadamente com o -onlyinargumento.

  • É meio lento, devido a system_profiler SPApplicationsDataType. Você pode precisar esperar um ou dois segundos antes da conclusão aparecer. Agora usa mdfindpara obter rapidamente os programas. Obrigado @Lri

  • Ele pode lidar com espaços em nomes de aplicativos e nomes de programas entre aspas, mas é bastante invasivo. Exige que a citação seja o primeiro caractere: Embora Scan" to "Pválido bash, este programa não o detectará. A conclusão também não funciona após um espaço de escape (por exemplo Scan\ to); use aspas nesses casos ( "Scan to). Suporte para espaços escaparam só é bom para completar DVDa DVD\ Player.


Não mdfind 'kMDItemKind==Application'seria mais rápido? Se completion-ignore-caseestiver ativado, o grep provavelmente também deve ignorar maiúsculas e minúsculas.
Lri

@Lri Você está certo. Não foi possível encontrar um caso em que esses resultados fizessem diferença.
9119 Daniel Beck

3

Preenchimento automático programável para o resgate! No entanto, eram necessárias muitas cópias da Página inicial de conclusão do Bash , que vale a pena instalar de qualquer maneira para muita mágica de conclusão automática. Se fizer isso, você precisará apenas da última função ( _open) e do comando de inicialização abaixo.

Adicione o seguinte a .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/
    # bash-completion-devel@lists.alioth.debian.org/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

Então, segui as instruções de instalação e adicionei o código a .bashrc. Agora, como faço para concluir automaticamente? O que eu envio para o preenchimento automático? (Desculpe, eu não posso ler o código)
daviesgeek

1
Não manipula nomes de programas com espaços (como DVD Player.app). Lista os diretórios /Applicationstambém (como iWork 09, por exemplo, entradas separadas iWorke 09), mas não os programas nele contidos.
Daniel Beck

1

Isso é ativado por padrão com o shell Zsh , desde que você tenha a própria conclusão ativada, é claro. O Zsh está incluído no OS X.

Tudo o que você precisa fazer é colocar autoload -Uz compinit; compinitseu ~ / .zshrc ou habilitar a conclusão através do primeiro menu de configuração de execução.

O Zsh é na verdade um superconjunto do Bash, então você não precisa aprender nada de novo. Até seus scripts provavelmente funcionarão!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.