Чи є спосіб автозавершити відкриту команду в Терміналі?


16

Я часто використовую open -a команду в Terminal для відкриття програм через ssh. Як зробити так, щоб автоматично заповнити ім’я програми?


Яку оболонку ви використовуєте?
Даніель Бек

2
Я думаю, що незначно швидшим способом було б набрати повний шлях (просто піди зі мною на деякий час !!), наприклад open -a /Applications/Textedit.app foo.txt(я припускаю, що це ти намагаєшся зробити). Якщо натиснути Tab після /Aз , /Applicationsа потім Tab знову після того , як /Teв /Textedit.appте , що повинно автозаповнення обидві частини для вас , як ви йдете. Зізнаюсь, не ідеально, але можливо, але краще. Це використовував Bash.
binarybob

Ви також можете спробувати наступні через інструкції в кінці цього поста: brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2
LRI

@DanielBeck Bash.
daviesgeek

Відповіді:


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

Третя версія, яка тепер повинна бути нечутливою до регістру і працювати в рамках цитат.


Я не міг з цим працювати DVD Player. Будь-які ідеї, що не так? Виглядає як Tab, а не пробіл ...
Даніель Бек

@DanielBeck Цього не було IFS=$'\n'. У всякому разі, я знову відредагував відповідь.
Лрі

Виглядає чудово. Пізній +1 для mdfindідеї. Приємна робота над оптимізацією та виправленнями. CoreServicesмабуть, особисто особисті переваги. У чому причина, nospaceхоча? Якщо є лише 1 програма, я хочу відразу продовжити відкриття файлу. Просто особисті переваги? Будь-яка ідея щодо решти питань цитування? AFAICT, це єдине, що залишилося для правильного рішення.
Даніель Бек

@DanielBeck Я завжди ставив -aпрапор наприкінці, тому, мабуть, -o nospaceце лише особисті переваги. Можливо, ми мусимо пінг Бретта Терпстра чи щось, щоб закінчити цей nerdfest ...
Lri

Дуже дякую!! @DanielBeck теж. Я вибрав версію Лрі через швидкість. На жаль, ваше було трохи повільним. Дякую вам обом! Ви мені дуже допомогли і зробили мій швидкість на Терміналі.
daviesgeek

7

Додайте до свого .bash_profileабо .bashrcі запустіть новий сеанс:

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

Не потрібно нічого встановлювати. Це працює з bashпоза коробкою.


Він автоматично заповнює імена програм, якщо попередній параметр є, -aі в іншому випадку буде показано поведінку за замовчуванням, наприклад, поверне список усіх файлів у поточному каталозі або заповнить поточний префікс шляху.

Результати генеруються з system_profiler SPApplicationsDataType, це найпростіший спосіб отримати всі програми, які можна запустити таким чином у вашій системі. Список обробляється лише для того, щоб повертати імена програм, які можуть містити пробіли і можуть відрізнятися від імен пакетів (навіть при ігноруванні .appсуфіксу)

Використання: введіть open -a, після чого пробіл, після чого натисніть Tabабо Esc(двічі в моїй системі, не впевнений, чи є вона скрізь).

Приклад, що показує всі допоміжні програми для мого сканера:

$ 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

Недоліки та проблеми цього рішення:

  • У вашій системі є багато програм, про які ви, можливо, не знаєте, як і все в /System/Library/CoreServices. Можливо, ви не хочете перераховувати їх. OTOH, це дуже легко побачити і запустити, наприклад, CharacterPaletteабо KeyboardViewerтаким чином. * Налаштуйте mdfindвиклики (дзвінки) відповідним чином за допомогою -onlyinаргументу.

  • Це якось повільно, через system_profiler SPApplicationsDataType. Можливо, вам доведеться почекати секунду чи дві, перш ніж з’явиться завершення. Тепер використовується mdfindдля швидкого отримання програм. Дякую @Lri

  • Він може обробляти пробіли у назвах програм та котирування доданих імен програм, але це досить хакі. Він вимагає, щоб цитата була першим символом: Хоча Scan" to "Pвона дійсна в bash, ця програма не виявить її. Завершення не працює після пропущеного місця (наприклад Scan\ to), використовуйте лапки в таких випадках ( "Scan to). Підтримка втекли просторів тільки добре завершити DVDдо DVD\ Player.


Не mdfind 'kMDItemKind==Application'було б швидше? Якщо completion-ignore-caseвстановлено, grep, ймовірно, також ігнорує випадок.
Лрі

@Lri Ти маєш рацію. Не вдалося знайти випадок, коли ці результати мали б значення.
Даніель Бек

3

Програмоване автодоповнення до допомоги! Потрібно було багато копіювання з домашньої сторінки Bash Completion , яку все одно варто встановити для магії автоматичного завершення. Якщо ви це зробите, вам знадобиться лише остання функція ( _open) та команда ініціалізації знизу.

Додайте до .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

Тому я дотримувався інструкцій із встановлення та додав код до .bashrc. Тепер, як дозволити його до автозаповнення? Що я натискаю на автоматичне завершення? (Вибачте, я не можу прочитати код)
daviesgeek

1
Не обробляє назви програм з пробілами (як DVD Player.app). Вказує також каталоги /Applications(як iWork 09окремі записи iWorkта 09), але не програми, що містяться в них.
Даніель Бек

1

Це ввімкнено за замовчуванням з оболонкою Zsh , якщо ви, звичайно, увімкнули саме завершення. Zsh включений в ОС X.

Все, що вам потрібно зробити, - це помістити autoload -Uz compinit; compinitу свій ~ / .zshrc або включити завершення через меню конфігурації першого запуску.

Zsh насправді здебільшого сукупність Bash, тому вам не потрібно було б дізнаватися нічого нового. Навіть ваші сценарії, ймовірно, спрацюють!

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