ターミナルでオープンコマンドを自動補完する方法はありますか?


16

open -a ターミナルでコマンドを頻繁に使用して、ssh経由でアプリケーションを開きます。アプリケーションの名前を自動補完するにはどうすればよいですか?


どのシェルを使用していますか?
ダニエルベック

2
少し速い方法は、フルパスを入力するopen -a /Applications/Textedit.app foo.txtことだと思います(ここでしばらく一緒に行くだけです!!)、例えば(あなたがやろうとしていることを仮定します)。あなたは後にTabキーを押した場合/A/Applications後に再びとタブ/Te/Textedit.app後、あなたが行くように、それはあなたのために、両方の部分を自動補完する必要があります。理想的ではありませんが、私は認めますが、多分良いでしょう。これはBashを使用していました。
binarybob

また、この記事の末尾にある指示によって、次の試みることができる:brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2
LRI

@DanielBeckバッシュ。
-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

3番目のバージョンは、大文字と小文字を区別せず、引用符で囲む必要があります。


これを使用できませんでしたDVD Player。何が間違っているのでしょうか?スペースではなくタブのように見えます...
ダニエルベック

@DanielBeck欠落​​していましたIFS=$'\n'。とにかく、答えをもう一度編集しました。

いいね。mdfindアイデアの遅延+1 。最適化と修正に関する素晴らしい作業。CoreServicesおそらく個人的な好みです。理由は何nospaceですか?プログラムが1つしかない場合は、ファイルを開いてすぐに続行します。個人的な好みですか?残りのクォーティング問題について何か考えはありますか?AFAICT、それが適切なソリューションに残された唯一のものです。
ダニエルベック

@DanielBeck私はいつも-a旗を最後に置いたので-o nospace、個人的な好みだと思います。多分私達は...このnerdfestを終了するブレット・テルプストラか何かにpingを実行する必要があります
LRI

どうもありがとうございます!!@DanielBeckあなたも。私はスピードのためにLriのバージョンを選びました。残念ながら、あなたは少し遅かったです。二人ともありがとう!あなたは私をたくさん助けてくれて、私のターミナルの速度を上げました。
-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、その後にスペースを入力してから、Tabor を押しますEsc(システム上で2回、どこにあるかわからない)。

スキャナーのすべてのヘルパーアプリケーションを示す例:

$ 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ます。完了が表示されるまで1〜2秒待つ必要がある場合があります。今すぐにmdfindプログラムを取得するために使用します。ありがとう@Lri

  • アプリケーション名のスペースと引用符で囲まれたプログラム名を処理できますが、かなりハックです。引用符を最初の文字にする必要があります:Scan" to "Pで有効ですがbash、このプログラムはそれを検出しません。エスケープされたスペースの後も補完は機能しません(例Scan\ to:)"Scan to。そのような場合は引用符を使用します()。エスケープされたスペースのサポートは、を完了DVDするのに適していDVD\ Playerます。


mdfind 'kMDItemKind==Application'速くなりませんか?completion-ignore-caseがオンに設定されている場合、grepはおそらく大文字と小文字を無視する必要があります。
-Lri

@Lriそうですね。これらの結果が違いを生むと思われるケースは見つかりませんでした。
ダニエルベック

3

救助のためのプログラム可能なオートコンプリート!ただし、Bash Completion Homepageから多くのコピーが必要でした。これは、多くのオートコンプリートマジックのためにインストールする価値があります。その場合、最後の関数(_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、などの個別のエントリiWork09)が、そこに含まれるプログラムは一覧表示しません。
ダニエルベック

1

もちろん、補完自体が有効になっている限り、これはデフォルトでZshシェルで有効になります。ZshはOS Xに含まれています。

あなたがしなければならないのはautoload -Uz compinit; compinit〜/ .zshrcに入れるか、最初の実行設定メニューで補完を有効にすることです。

Zshは実際にはほとんどがBashのスーパーセットであるため、新しいことを学ぶ必要はありません。スクリプトでさえもおそらく動作します!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.