Bashで中括弧を使用するときにタブの完成を取得する方法

Bashで中括弧を使用するときにタブの完成を取得する方法

Bashのコマンドで中括弧を使用するときは、タブ補完機能を使用したいと思います。

たとえば、

cp ~/html/{foo bar.txt whatever} /var/www/html/

中かっこで指定されたファイルのタブを完成させたい。

答え1

これを解釈する方法は2つあります。 endの前に名前を入力すると、完成したい}(他のディレクトリでファイルの完成を効果的に実行します)。または、拡張が完了し、endの後の(有効な)名前を変更しようとします}{ }拡張機能は、拡張されたグロービングとは異なり、すべてのオプションを拡張します。既存のファイル名を指定しますが、スペースの代わりに「、」を使用してください。

{}Bashを使用して単語リストを作成するための予想される方法は次のとおりです。

cp ~/html/{foo,bar.txt,whatever}  ...

2つのオプションがあります。 readline キーバインディングをシェル関数にリンクするか、プログラムで行うことです。

readlineメソッドを使用すると、現在のコマンドを完全に書き直すことができますが、問題は現在のコマンドラインを表示しないため、解析の問題が少なくないことです。

プログラム可能な完成するpath/{コマンドラインをトークン化しますが、現在の単語のみを変更/置換できます。つまり、編集中にプレフィックスを(簡単に)保持することはできません。

関連する唯一の基本的なbash機能は、bashがデフォルトで(Esc)にバインドされた「すべてのシェルワード拡張」を実行すると主張するreadline機能です。これらの拡張は、マニュアルページ(bash-4.3)に示されている7つの拡張タイプのすべてであると合理的に期待できます。shell-expand-line\M-\C-e\C-e

Expansion is performed on the command line after it has been split into
words.   There are seven kinds of expansion performed: brace expansion,
tilde expansion, parameter and variable  expansion,  command  substitu‐
tion, arithmetic expansion, word splitting, and pathname expansion.

入力して試すことができます(Enterを押す必要はありません)。

echo {1..2} ~root $0 $LANG `echo foo` $((1+2) "a b" /etc/p[aeiou]*

次にMetaCtrlE(+メタ障害のあるキーボードを使用している場合ESC)。CtrlE

最初と最後の(中かっことパス)拡張の両方が機能しないため、ドキュメントと実装はIMHOと一致しません。

以下は、[拡張]タブを使用する完全なソリューションではなく、回避策です。ただし、正しい中括弧拡張構文を使用する必要があり、特に空白ではなくカンマを使用して項目を区切る必要があります。

function _expand() {
   [[ -z "${READLINE_LINE}" ]] && return
   eval local aa=( ${READLINE_LINE} )       # not-quoted, eval needed
   [[ ${#aa} -eq 0 ]] && return             # parse problem
   printf -v READLINE_LINE "%s " "${aa[@]}"
   READLINE_POINT=${#READLINE_LINE}         # eol, predictable at least
}

bind -x '"\C-_":_expand'

これは配列を埋め、すべての通常の拡張(上記のレコードを除く)が発生するようにし、コマンドラインを再構築するCtrl_bash関数に関連付けられています。eval

入力を開始し、Ctrl_何かを展開したいときにクリックし、Return準備ができたら通常のキーを押します。

これはタブよりも強力ですが、入力行全体を拡張するため、精度が低下します。特に、さまざまなシェルメタ文字が単純なevalロジックを難読化する場合、期待どおりに拡張されないことがあります。

zshBashソリューションを過度にエンジニアリングするのではなく、Gilleの提案を見る価値があります。

答え2

CtrlUbuntu(16.04)端末で+操作を実行すると、ディレクトリ内{{ファイルを使用して中括弧が自動的に完成します。ファイルを区切るためにスペースの代わりにコンマを使用します。たとえば、次のファイルを含むディレクトリです。 file.cpp file.h file.i file.py file_wrap.cxx

...自動的に行われます。 $ cp file{.{cpp,h,i,py},_wrap.cxx}

答え3

この文脈では、中括弧(定義上「中括弧」)は、カンマ区切りのテキストフラグメントのリストを表します。ファイル名に最も一般的に使用されますが、拡張されます。今後ファイル名拡張子を処理します。したがって、bash実際にファイル名を入力しているかどうかを知る方法がないため、明示的な拡張機能はありません。

答え4

OPは、タップ後の行補完の動作を直接観察し、戻り後の解析動作を比較できる診断ツールを提供しました。観察と分析の後に中かっこ機能を完成させるために行補完関数を作成することは可能ですが、 bash は中かっこ以降の追加の行完成機能を抑制するように制限するので、これは意味がないと結論付けることができます。

以下のbashスクリプトを使用すると診断が可能です。

#!/bin/bash

confirm_args(){
    logger -t "confirm_args" -- "#=${#}"
    for index in `seq 0 ${#}` ; do
        eval item=\$$index
        logger -t "confirm_args" -- "[$index] ${item}"
    done    
}

_foo_completion(){
    logger -t "_foo_completion" -- "COMP_CWORD=${COMP_CWORD}" 
    logger -t "_foo_completion" -- "#COMP_WORDS=${#COMP_WORDS[@]}"
    for index in `seq 0 $((${#COMP_WORDS[@]}-1))` ; do
        logger -t "_foo_completion" -- "[$index] ${COMP_WORDS[$index]}"
    done
}
declare -f _foo_completion
complete -F _foo_completion "foo"
alias foo=confirm_args

私はこれを要点として提供しましたfoo-completion.sh

コピーしてファイルに貼り付けます/tmp/foo-completion.sh

2つのダミーファイルの生成

touch /tmp/a.{1,2}

診断が正しく機能するには、loggerシステムログを作成する必要があります。これにより、OPはシステムログファイルを追跡して診断出力を表示できます。 OPが実行されている場合は、systemd新しいウィンドウを開き、次のように入力して確認できます。

sudo journalctl -f

ライン完成と診断出力を有効にする:

source /tmp/foo-completion.sh

完了は実行されないため、候補_foo_completionはユーザーに返されません。行補完関数にどのデータが渡されたかを示すだけです。

いくつかの入力をテストし、出力を観察します。

1を入力してください

foo a.*[SPACE][TAB]

出力

Jul 23 12:10:34 ub18 _foo_completion[17672]: COMP_CWORD=2
Jul 23 12:10:34 ub18 _foo_completion[17673]: #COMP_WORDS=3
Jul 23 12:10:34 ub18 _foo_completion[17675]: [0] foo
Jul 23 12:10:34 ub18 _foo_completion[17676]: [1] /tmp/a.*
Jul 23 12:10:34 ub18 _foo_completion[17677]: [2]

2と入力してください

foo a.*[SPACE][RETURN]

出力

Jul 23 12:19:43 ub18 confirm_args[18487]: #=2
Jul 23 12:19:43 ub18 confirm_args[18489]: [0] bash
Jul 23 12:19:43 ub18 confirm_args[18490]: [1] /tmp/a.1
Jul 23 12:19:43 ub18 confirm_args[18491]: [2] /tmp/a.2

3と入力してください

foo a.{1,2}[SPACE][TAB]

出力

注 - 出力はありません!

4を入力してください

foo a.{1,2}[SPACE][RETURN]

出力

Jul 23 12:28:42 ub18 confirm_args[19098]: #=2
Jul 23 12:28:42 ub18 confirm_args[19100]: [0] bash
Jul 23 12:28:42 ub18 confirm_args[19101]: [1] /tmp/a.1
Jul 23 12:28:42 ub18 confirm_args[19102]: [2] /tmp/a.2

分析する

「INPUT 1」では、*リテラル文字「*」で行補完機能に渡されます。ちなみに、「INPUT 3」では、改行機能も呼び出されません。明らかに中括弧のため、bashは行補完機能への追加呼び出しを抑制します。

一方、[RETURN]解析後のケースでは2と入力してくださいそして4を入力してください、bashは両方のケースを拡張し、a.*同じa.{1,2}結果を得ます。

テストケースもあります:

5を入力してください

foo a.{[TAB]

出力

Jul 23 12:56:52 ub18 _foo_completion[21059]: COMP_CWORD=1
Jul 23 12:56:52 ub18 _foo_completion[21060]: #COMP_WORDS=2
Jul 23 12:56:52 ub18 _foo_completion[21062]: [0] foo
Jul 23 12:56:52 ub18 _foo_completion[21063]: [1] /tmp/a.{

分析する

「INPUT 5」、bashのタブ文字の前にスペースはありません。する通話回線が完了しました。したがって、理論的には、行補完は単一の候補を返すことができます。

/tmp/a.{1,2}

これによりオートコンプリートが発生します(まだテストしていませんが)。

これ質問それはもっと遠く中カッコは行補完を抑制するため、行補完を使用してファイルを追加することはできません。

既存の行補完機能を使用してテストします。

入力確認

ls /tmp/a.{[TAB][TAB][TAB][TAB][TAB][TAB]

出力

(何もありません)

bashがファンシーの後にラインの完成を抑制しない限り、ライン完​​成機能でファンシーをサポートする価値がないという主張を支持するようです。

[CTRL]{{編集:で説明した方法を使用した後この回答、私はそれが完了し(時々)、より多くのファイルを追加するための基本的な完成機能に従うことができることがわかりました。ただし、これ以降は元の機能は使用できなくなり、_foo_completion使用量によっては制限になる場合もありません。

関連情報