Apakah ada cara untuk melengkapi secara otomatis perintah terbuka di Terminal?

16

Saya sering menggunakan open -a perintah di Terminal untuk membuka aplikasi melalui ssh. Bagaimana cara membuatnya secara otomatis melengkapi nama aplikasi?

daviesgeek
sumber
Shell apa yang Anda gunakan?
Daniel Beck
2
Saya kira cara yang sedikit lebih cepat adalah dengan mengetikkan path lengkap (hanya pergi dengan saya untuk sementara waktu di sini !!), misalnya open -a /Applications/Textedit.app foo.txt(saya berasumsi itulah yang Anda coba lakukan). Jika Anda menekan Tab setelah /Adari /Applicationsdan kemudian Tab lagi setelah /Tedari /Textedit.appmaka yang harus melengkapi otomatis kedua bagian untuk Anda sebagai Anda pergi. Tidak ideal, saya akui, tapi mungkin sedikit lebih baik. Ini menggunakan Bash.
binarybob
Anda juga dapat mencoba mengikuti petunjuk di akhir posting ini: brettterpstra.com/grabbing-a-mac-apps-icon-advanced-bash-usage-2
Lri
@DanielBeck Bash.
daviesgeek

Jawaban:

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

Versi ketiga, yang sekarang harus peka huruf besar kecil dan berfungsi dalam tanda kutip.

Lri
sumber
Saya tidak bisa menyelesaikannya DVD Player. Ada ide apa yang salah? Sepertinya Tab bukan spasi ...
Daniel Beck
@DanielBeck Itu hilang IFS=$'\n'. Lagi pula, saya mengedit jawabannya lagi.
Lri
Kelihatan bagus. +1 terlambat untuk mdfindgagasan itu. Kerja bagus untuk optimasi dan perbaikan. CoreServicesmungkin preferensi pribadi. Apa alasannya nospace? Jika hanya ada 1 program, saya ingin langsung melanjutkan dengan membuka filen. Hanya preferensi pribadi? Adakah gagasan tentang masalah kutipan yang tersisa? AFAICT, itulah satu-satunya yang tersisa untuk solusi yang tepat.
Daniel Beck
@DanielBeck Saya selalu meletakkan -abendera di bagian akhir, jadi saya kira -o nospaceitu hanya pilihan pribadi. Mungkin kita harus melakukan ping Brett Terpstra atau sesuatu untuk menyelesaikan nerdfest ini ...
Lri
Terima kasih banyak!! @DanielBeck juga. Saya memilih versi Lri karena kecepatannya. Sayangnya, milikmu agak lambat. Terima kasih banyak! Anda telah banyak membantu saya dan membuat kecepatan Terminal saya meningkat.
daviesgeek
7

Tambahkan yang berikut ke Anda .bash_profileatau .bashrcdan luncurkan sesi baru:

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

Tidak perlu menginstal apa pun. Ini berfungsi dengan di bashluar kotak.


Ini hanya akan melengkapi nama program secara otomatis jika opsi sebelumnya -amenunjukkan perilaku default, misalnya mengembalikan daftar semua file di direktori saat ini atau menyelesaikan awalan jalur saat ini.

Hasilnya dihasilkan dari system_profiler SPApplicationsDataType, yang merupakan cara termudah untuk mendapatkan semua aplikasi yang dapat diluncurkan dengan cara ini pada sistem Anda seperti itu. Daftar diproses untuk hanya mengembalikan nama-nama program, yang dapat berisi spasi dan dapat berbeda dari nama bundel (bahkan ketika mengabaikan .appsuffix)

Penggunaan: Ketik open -a, diikuti spasi, diikuti dengan menekan Tabatau Esc(dua kali pada sistem saya, tidak yakin apakah ada di mana-mana).

Contoh memperlihatkan semua aplikasi pembantu untuk pemindai saya:

$ 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

Kelemahan dan masalah dari solusi ini:

  • Ada banyak program di sistem Anda yang mungkin tidak Anda sadari, seperti semua yang ada di dalamnya /System/Library/CoreServices. Anda mungkin tidak ingin mendaftar semuanya. OTOH, sangat mudah dilihat dan diluncurkan misalnya CharacterPaletteatauKeyboardViewer dengan cara ini. * Konfigurasikan mdfindpanggilan dengan -onlyinargumen yang tepat.

  • Agak lambat, karena system_profiler SPApplicationsDataType. Anda mungkin perlu menunggu satu atau dua detik sebelum selesai muncul. Sekarang gunakanmdfind untuk mendapatkan program dengan cepat. Terima kasih @Lri

  • Itu dapat menangani spasi dalam nama aplikasi, dan kutipan nama program terlampir, tapi itu agak hacky. Ini membutuhkan kutipan untuk menjadi karakter pertama: Meskipun Scan" to "Pvalid bash, program ini tidak akan mendeteksinya. Penyelesaian tidak berfungsi setelah ruang yang lolos baik (misalnya Scan\ to), gunakan tanda kutip dalam kasus tersebut ( "Scan to). Dukungan untuk ruang lolos hanya baik untuk menyelesaikan DVDke DVD\ Player.

Daniel Beck
sumber
Bukankah mdfind 'kMDItemKind==Application'lebih cepat? Jika completion-ignore-casediaktifkan, grep mungkin juga harus mengabaikan case.
Lri
@Lri Anda benar. Tidak dapat menemukan kasus di mana hasil ini akan membuat perbedaan.
Daniel Beck
3

Pelengkapan otomatis terprogram untuk penyelamatan! Diperlukan banyak penyalinan dari Bash Completion Homepage , yang tetap layak diinstal untuk banyak keajaiban pelengkapan otomatis. Jika ya, Anda hanya perlu fungsi terakhir ( _open) dan perintah inisialisasi dari bawah.

Tambahkan yang berikut ke .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
sumber
Jadi saya mengikuti instruksi instal dan menambahkan kode ke .bashrc. Sekarang bagaimana cara mendapatkannya secara otomatis? Apa yang saya dorong ke pelengkapan otomatis? (Maaf, saya tidak bisa membaca kodenya)
daviesgeek
1
Tidak menangani nama program dengan spasi (seperti DVD Player.app). Daftar direktori /Applicationsjuga (seperti iWork 09, sebagai entri iWorkdan terpisah 09), tetapi tidak ada program yang terkandung di dalamnya.
Daniel Beck
1

Ini diaktifkan secara default dengan shell Zsh , selama Anda telah menyelesaikannya dengan sendirinya, tentu saja. Zsh termasuk dalam OS X.

Yang harus Anda lakukan adalah meletakkan autoload -Uz compinit; compinit ~ / .zshrc Anda, atau mengaktifkan penyelesaian melalui menu konfigurasi jalankan pertama.

Zsh sebenarnya sebagian besar superset dari Bash, jadi Anda tidak perlu mempelajari hal baru. Bahkan skrip Anda mungkin akan berfungsi!

SilverWolf - Pasang kembali Monica
sumber