
Eu tenho um script bash chamado findme
, que é codificado da seguinte forma:
#!/bin/bash
locate -Abi '*\.'$1 $2 | grep --color=always -ni $2 | less -R
Ele procura todos os arquivos com uma extensão de arquivo especificada (primeiro argumento fornecido ao script) que possui um padrão (o próximo argumento fornecido) em seu nome de arquivo.
Se eu executar o seguinte:
user@machine$ findme pdf classifi
Ele procurará todos pdf
os arquivos classifi
em seu nome de arquivo. Portanto, posso obter algo como o seguinte resultado.
1:/home/usuário/Dropbox/SharedWithFriends/math/classificarcations2000.pdf
2:/home/usuário/Dropbox/SharedWithFriends/math/classificarcações2010.pdf
A questão é: "Você pode me fornecer um código de script bash no qual, após mostrar os resultados, peça um número e um visualizador para automatizar meu próximo trabalho?"
por exemplo eu gostaria, se eu inserir:
> 2 evince
o script é executado evince
no 2
segundo item do resultado da pesquisa,ou seja, se foi isso que eu digitei no resultado da pesquisa anterior, ele executa:
evince /home/user/Dropbox/SharedWithFriends/math/classifications2010.pdf
Responder1
Aqui está uma variação da sua findme
função que obtém os resultados, mas em vez de usá grep
-los para numerá-los ou less
paginá-los, ela os lista em uma matriz interna e solicita a escolha do item e do programa.
#!/usr/bin/env bash
readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2" | grep --color=always -i "$2")
for((i=1; i <= ${#results[*]}; i++))
do
printf "%d: %s\n" $i "${results[i]}"
done
read -p "> " item program
$program "${results[item]}"
Adicionei algumas citações ao seu script original para lidar melhor com espaços em nomes de arquivos ou até mesmo com parâmetros grep. Ajustei a readarray
chamada para que os resultados comecem no índice 1 em vez de 0, para que corresponda à numeração do grep.
Responder2
Observe que seu findme
script tem alguns problemas:
- Faltando aspas duplas em torno de substituições de variáveis
- A saída de
grep --color=always
produz resultados que não podem ser usados em uma substituição de comando. Você precisa passarless
, mas não tente reutilizá-lo em um script. - grep e localizar usam sintaxe de padrão diferente, portanto, usar
grep
para colorir o segundo argumento nem sempre funcionará. Passar-r
paralocate
faz com que ele use regexps, mas com a sintaxe do Emacs que é um pouco diferente das sintaxes suportadas pelo grep.
No bash, você pode usarmapfile
para colocar algumas linhas de forma confiável em uma matriz. Combine-o comsubstituição de processopara usar a saída de um comando. Em seguida, imprima esse array e leia a entrada do usuário.
findrun () {
mapfile search_hits <(locate -Abir ".*\.$1" "$2")
print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2"
if read -a cmd; then
set -- "${cmd[@]}"
set -- "$@" "${search_hits[$1]}"
shift
"$@"
fi
}
Uma interface alternativa seria definir os parâmetros posicionais. É um pouco complicado, porque você não pode alterar os parâmetros posicionais de uma função, mas há ummaneira indireta de fazer isso no bashusando um alias e fornecendo um script. Cuidado ao citar.
alias findrun='. <(echo findrun_prepare \"\$@\"; echo set -- "\"\${search_hits[@]}\"")'
findrun_prepare () {
mapfile search_hits <(locate -Abir ".*\.$1" "$2")
print '%s\n' "${search_hits[@]}" | grep --color=always -ine "$2" >&2
}
Uso:
findrun pdf classifi
evince "$2"
Responder3
Baseado na solução dada por Jeff Schaller. Encontrei uma solução, ficaria feliz se recebesse seus comentários, para melhorar.
#!/bin/bash
readarray -O 1 -t results < <(locate -Abi '*\.'"$1" "$2")
for((i=1; i <= ${#results[*]}; i++))
do
printf "%d: %s" $i "${results[i]}" | grep --color=always -i "$2"
done
read -p "> " item program
$program "${results[item]}"
Parece uma resposta simples (até a complexidade dos tópicos).
Mas não é suficiente se os resultados forem superiores a um determinado número! Nesse caso, precisamos de algo como more
ouless