O script a seguir play_movie.sh
destina-se a selecionar automaticamente um filme se houver apenas um no diretório atual e reproduzi-lo com ffplay
. Caso contrário, destina-se a exibir uma seleção de filmes ao usuário e obter informações deles (o filme a ser reproduzido).
#!/usr/bin/bash
output_a=$(ls -R *.[aA][vV][iI] 2>/dev/null)
output_m=$(ls -R *.[mM][kKpP][vV4]] 2>/dev/null)
output_v=$(ls -R *.[vV][oO][bB]] 2>/dev/null)
all_exts="${output_a}${output_m}${output_v}"
ln_cnt=$(echo "${all_exts}" | wc -l)
if [[ "$ln_cnt" -eq 1 ]]; then
echo -e "Playing: ${all_exts}\n"
ffplay -hide_banner -infbuf -fs -sn -ast a:0 "${all_exts}"
elif [[ "$ln_cnt" -gt 1 ]]; then
printf "Select a file out of the list below"
ls -R *.[aA][vV][iI] 2>/dev/null
ls -R *.[mM][kKpP][vV4] 2>/dev/null
ls -R *.[vV][oO][bB] 2>/dev/null
read line; ffplay -hide_banner -infbuf -fs -sn -ast a:0 "$line"
fi
O problema que tenho com este script:
- O script executa a primeira ramificação da
if
instrução mesmo se houver muitos filmes no diretório atual. Então eu entendoNo such file or directory
. - Se houver apenas um filme para ser exibido, eu ganho
No such file or directory
.
Tive dificuldade em confiar na saída do ls
passado. É possível corrigir esse script sem a necessidade de usar find
?
Supondo que a parte “se houver apenas um no diretório atual” esteja correta ( ou seja , você só se preocupa com os arquivos no diretório atual), você pode evitar o uso
ls
, e muito menosfind
:Isso define
nullglob
para que os globs sem correspondências sejam removidos e, em seguida, define os parâmetros para todos os arquivos correspondentes.Conforme ilustrado na resposta de Stéphane Chazelas , você pode usar
select
para melhorar a experiência do usuário (select
usa os parâmetros posicionais por padrão, o que combina perfeitamente com o usoset
acima):Você não pode usar
ls
assim. Esses*.[aA][vV][iI]
são expandidos pelo shell, nãols
, o-R
forls
é para eleR
listar ecursivamente o conteúdo dos diretórios, para os quais você precisa passar o caminho dos diretórios, não dos arquivos, e mesmo assim, ele geraria a lista de arquivos (qualquer arquivos não ocultos) nesses diretórios sem seus componentes de diretório, portantoffmpeg
não foi possível encontrá-los.Além disso, a menos que você use a
--zero
opção de versões muito recentes da implementação GNU dels
, a saída dels
simplesmente não será pós-processável de forma confiável.Aqui, para encontrar arquivos com essa lista de extensões em qualquer lugar do diretório de trabalho atual e abaixo, você usaria
find
. Para armazenar uma lista de arquivos (ou qualquer coisa importante), você usa uma variável de array, não uma variável de string/escalar.Usar
zsh
em vez debash
aqui tornaria tudo muito mais fácil, pois zsh tem (funcionando corretamente) globbing recursivo e qualificadores glob, o que significa que você também pode restringir a lista de arquivos àqueles do tipo regular . Globs também ignoram arquivos ocultos por padrão (como,ls
mas nãofind
onde você precisa pular manualmente):Com
bash
(o shell GNU) + GNUfind
, você poderia fazer algo parecido com:Algumas outras notas:
echo -e
quebraria para nomes de arquivos que contenham\
caracteres. Aqui você não deseja que ase
sequências de escape sejam expandidas, daí o-E
forecho
ou-r
forprint
. Se você quiser imprimir uma nova linha extra, adicione-a ao último argumentoecho
literalmente ou com$'\n'
. Observe também quebash
'secho
só aceita opções se ouposix
nãoxpg_echo
estiver definido (e eles são definidos por padrão em alguns sistemas e/ou ambientes). Geralmente,echo
é melhor evitar usar, eu ainda o uso aqui por sua capacidade de imprimir facilmente seus argumentos unidos com espaços (o que é mais complicado de fazerprintf
, e o bash só temprint
como um plugin carregável cujos poucos sistemas foram incluídos por padrão quando possuem bash) e porque sabemos que o shell ébash
, então aplay
função pode ser usada para reproduzir mais de um vídeo por vez.select
vai a saída, por exemplo.IFS= read -r line
, nãoread line
. Mas, em qualquer caso, os caminhos dos arquivos não precisam ser compostos por uma única linha, pois o caractere de nova linha é tão válido quanto qualquer outro em um nome de arquivo.*.[mM][kKpP][vV4]
também corresponderia afiles.mv4
(nãom4v
).