有没有一种方法可以自动完成Terminal中的open命令?


16

我经常open -a 在终端中使用命令通过ssh打开应用程序。如何使其自动完成应用程序的名称?


您正在使用什么外壳?
Daniel Beck

2
我想稍微快一点的方法是键入完整路径(例如,在这里和我一起走一会儿!),例如open -a /Applications/Textedit.app foo.txt(我假设这就是您要尝试的操作)。如果您在/Aof 之后按Tab /Applications,然后在/Teof /Textedit.app之后再次按Tab ,那么这将为您自动完成这两个部分。我承认这并不理想,但也许更好。这是使用Bash。
binarybob 2012年

您也可以尝试按照此帖子结尾处的说明进行操作:brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2
Lri 2012年

@DanielBeck Bash。
daviesgeek

Answers:


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。任何想法有什么问题吗?看起来像标签,而不是空格...
Daniel Beck

@DanielBeck它不见了IFS=$'\n'。无论如何,我再次编辑了答案。
Lri 2012年

看起来不错。这个mdfind想法晚了+1 。优化和修复方面的出色工作。CoreServices虽然可能是个人喜好。到底是什么原因nospace呢?如果只有1个程序,我想立即继续打开文件。只是个人喜好?对剩余的报价问题有任何想法吗?AFAICT,这是找到适当解决方案的唯一途径。
Daniel Beck

@DanielBeck我总是将-a标志放在最后,因此我想-o nospace这只是个人喜好。也许我们应该ping Brett Terpstra或其他事情来完成这个书呆子……
Lri 2012年

非常感谢!!@DanielBeck你也是。由于速度原因,我选择了Lri的版本。不幸的是,您的速度有点慢。非常感谢你们俩!您为我提供了很多帮助,并提高了我的终端速度。
daviesgeek '02

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,后跟一个空格,然后按TabEsc(在我的系统上两次,不确定是否到处都是)。

显示我的扫描仪的所有帮助程序的示例:

$ 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)。为逃脱的空间支持只是很好的完成DVDDVD\ Player


会不会mdfind 'kMDItemKind==Application'更快?如果completion-ignore-case设置为on,则grep可能也应该忽略大小写。
Lri 2012年

@Lri你是对的。找不到这些结果会有所作为的情况。
Daniel Beck

3

可编程自动补全功能!不过,需要从Bash完成主页进行大量复制,无论如何,对于许多自动完成魔术来说,还是值得安装的。如果这样做,则只需要最后一个功能(_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'2

1
不处理带有空格的程序名称(如DVD Player.app)。同时列出目录/Applications(例如iWork 09,作为单独的条目iWork09),但不列出其中包含的程序。
Daniel Beck

1

当然,默认情况下,只要启用了完成功能,Zsh shell就会默认启用功能。Zsh包含在OS X中。

您所需要做的只是放在autoload -Uz compinit; compinit〜/ .zshrc中,或者通过第一个运行配置菜单启用完成功能。

Zsh实际上实际上是Bash的超集,因此您不必学习任何新知识。甚至您的脚本也可能有效!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.