Existem duas maneiras de interpretar a pergunta: você deseja a conclusão enquanto digita os nomes antes do fechamento }
(executando a conclusão de arquivos em outro diretório); ou você deseja que a conclusão expanda e substitua os nomes (válidos) após o fechamento de }
. A expansão { }
expande todas as opções, ao contrário da globbing, que expande os nomes dos arquivos existentes , embora usando "," em vez de espaço.
Com o bash, a maneira esperada de usar {}
para criar uma lista de palavras é:
cp ~/html/{foo,bar.txt,whatever} ...
Existem duas opções: associar uma ligação de tecla readline a uma função shell ou conclusão programável.
A abordagem readline oferece uma mão livre para reescrever completamente o comando atual, mas o problema é que ele não separa a linha de comando atual, então você tem um problema de análise não-trivial.
A conclusão programável faz tokenizar a linha de comando, mas você só pode modificar / substituir a palavra atual, o que significa que você não pode (facilmente) preservar o prefixo path/{
durante a edição.
O único recurso bash nativo relacionado é o readline
function shell-expand-line
para o bash pretende fazer "todas as expansões de palavra do shell", isso é vinculado por padrão a \M-\C-e
(Esc \C-e
). Pode-se razoavelmente esperar que esta expansão seja todos os sete tipos de expansão indicados na página man (bash-4.3):
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.
Você pode experimentar digitando (sem pressionar Voltar)
echo {1..2} ~root $0 $LANG 'echo foo' $((1+2) "a b" /etc/p[aeiou]*
E então Meta Ctrl E (ou ESC + Ctrl E se você estiver usando um teclado Meta-impaired).
Nem a primeira nem a última expansão (chave e caminho) funcionam para mim, então a documentação e a implementação não combinam com a IMHO.
O que se segue é uma solução alternativa, em vez de completa, usando a guia para expansão. Você precisa se certificar de usar a sintaxe correta para a expansão de chaves, especificamente com uma vírgula para separar os itens, não um espaço.
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'
Isto liga Ctrl _ a uma função bash que usa eval
para preencher uma matriz, causando todas as expansões normais (como acima, e não incluindo histórico) para ocorrer e, em seguida, recria a linha de comando.
Comece a digitar, pressione Ctrl _ quando quiser algo expandido e Retornar como normal quando estiver pronto.
Isso é mais poderoso que a guia, mas menos preciso, pois expande a linha de entrada completa. Existem alguns casos em que isso não se expandirá como esperado, especificamente onde vários metacaracteres de shell confundem a lógica eval
simples.
Em vez de projetar uma solução bash em excesso, a sugestão de zsh
de Gille vale a pena.