Posso selecionar apenas um resultado de um bash glob?

14

Estou tentando escrever um script para o trabalho para automatizar alguns relatórios em uma saída. Os arquivos de log são (atualmente, estão sendo 'padronizados' no futuro) armazenados neste tipo de estrutura de caminho:

/<root_path>/<process_one_path>/logs/<time_date_stamp>/<specific_log_file>

/<root_path>/<process_two_path>/logs/<different_time_date_stamp>/<specific_log_file>

Todas as partes do caminho são conhecidas, exceto os carimbos de data e hora, que são sempre os mais recentes na pasta.

Se eu tentar usar um curinga no lugar do carimbo de data e hora, obtenho vários resultados, por exemplo:

> ls /<root_path>/<process_two_path>/logs/* [tab]
20130102-175103
20130118-090859
20130305-213506

Eu só quero que ele retorne o mais recente, isso é possível com o Bash?

NB (eu não tenho zsh, e por mais adorável que pareça, duvido que possamos fazê-lo funcionar)

Pureferret
fonte

Respostas:

9

O seguinte funciona no bash 4.2:

list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[-1]}"

Se o seu bash for uma versão mais antiga:

list=( /<root_path>/<process_two_path>/logs/* )
echo "${list[${#list[@]}-1]}"
Patrick
fonte
Definitivamente, isso funciona no meu computador doméstico, mas não posso garantir que funcione no trabalho?
Pureferret
@Pureferret a parte que pode não funcionar é o índice negativo da matriz ( -1). Isso foi adicionado no bash 4.2. O RHEL5 é provavelmente a distribuição corporativa mainstream suportada mais antiga disponível e usa o bash 4.2.20.
Patrick
1
As versões mais antigas do bashhave: "${list[@]: -1}"like in ksh93( [-1]vem de zsh).
Stéphane Chazelas
@Patrick - RHEL5 usa bash 3.2. RHEL 3 e 4 ainda suportado por vida útil prolongada.
Jordanm #
1
@Pureferret Você também pode fazer aritmética com o comprimento do array, veja minha edição.
Gilles 'SO- stop being evil'
10

POSIXly:

 set -- /<root_path>/<process_two_path>/logs/*
 shift "$(($# - 1))"
 printf '%s\n' "$1"

Desde que você mencionou zsh:

 print -r /<root_path>/<process_two_path>/logs/*([-1])
Stéphane Chazelas
fonte
4

Use o bash glob em um loop for do bash. Como isso:

for filename in <logdir>/*; do :; done; echo "$filename"

Isso depende do fato de que o bash faz a expansão glob classificada em ordem alfabética. Leia o manual do bash para mais informações. Observe que isso depende de LC_COLLATE . Isso também depende do fato de que a variável filenameainda contém o último valor após o encerramento do loop.

Se você quiser o nome do arquivo com o carimbo de data / hora mais antigo, faça o seguinte:

for filename in <logdir>/*; do echo "$filename"; break; done
lesmana
fonte
1

-1 é o padrão nos pipelines e a saída ls já deve estar classificada:

ls | tail -n1

Se outras pessoas procuravam como inserir o primeiro ou o último resultado interativamente, você pode vincular menu completo ou menu completo para trás em .inputrc:

"\e\t": menu-complete
"\e[Z": menu-complete-backward # shift-tab

Se show-all-if-ambiguous estiver ativado, set completion-query-items 0o prompt será removido quando houver 101 ou mais resultados e set page-completions offdesabilitado o pager.

Lri
fonte