AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 754645
Accepted
John Smith
John Smith
Asked: 2023-08-22 16:20:17 +0800 CST2023-08-22 16:20:17 +0800 CST 2023-08-22 16:20:17 +0800 CST

Como capturar de forma confiável a saída de 'ls' neste script?

  • 772

O script a seguir play_movie.shdestina-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:

  1. O script executa a primeira ramificação da ifinstrução mesmo se houver muitos filmes no diretório atual. Então eu entendo No such file or directory.
  2. Se houver apenas um filme para ser exibido, eu ganho No such file or directory.

Tive dificuldade em confiar na saída do lspassado. É possível corrigir esse script sem a necessidade de usar find?

ls
  • 2 2 respostas
  • 401 Views

2 respostas

  • Voted
  1. Best Answer
    Stephen Kitt
    2023-08-22T16:49:46+08:002023-08-22T16:49:46+08:00

    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 menos find:

    #!/usr/bin/bash -
    
    shopt -s nullglob
    set -- *.[aA][vV][iI] *.[mM][kKpP][vV4] *.[vV][oO][bB]
    
    if [[ "$#" -eq 1 ]]; then
      printf>&2 "Playing: %s\n\n" "$@"
      ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$@"
    elif [[ "$#" -gt 1 ]]; then
      printf>&2 "Select a file out of the list below:\n"
      printf>&2 "%s\n" "$@"
      IFS= read -r line &&
        ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$line"
    fi
    

    Isso define nullglobpara 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 selectpara melhorar a experiência do usuário ( selectusa os parâmetros posicionais por padrão, o que combina perfeitamente com o uso setacima):

    #!/usr/bin/bash -
    
    shopt -s nullglob
    set -- *.[aA][vV][iI] *.[mM][kKpP][vV4] *.[vV][oO][bB]
    
    if [[ "$#" -eq 1 ]]; then
      printf>&2 "Playing: %s\n\n" "$@"
      ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$@"
    elif [[ "$#" -gt 1 ]]; then
      select video; do
        ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$video"
        exit
      done
    fi
    
    • 10
  2. Stéphane Chazelas
    2023-08-22T16:54:46+08:002023-08-22T16:54:46+08:00

    Você não pode usar lsassim. Esses *.[aA][vV][iI]são expandidos pelo shell, não ls, o -Rfor lsé para ele Rlistar 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, portanto ffmpegnão foi possível encontrá-los.

    Além disso, a menos que você use a --zeroopção de versões muito recentes da implementação GNU de ls, a saída de lssimplesmente 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 zshem vez de bashaqui 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, lsmas não findonde você precisa pular manualmente):

    #! /usr/bin/zsh -
    set -o extendedglob
    videos=( **/*.(#i)(avi|mkv|mp4|vob)(N-.) )
    
    play() {
      print -ru2 Playing $argv
      ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- $argv
    }
    
    case $#videos in
      (0) print -u2 No video found; exit 1;;
      (1) play $videos;;
      (*) print -u2 Select a video:
          select video in $videos; do
            play $video || exit
            break
          done;;
    esac
    

    Com bash(o shell GNU) + GNU find, você poderia fazer algo parecido com:

    #! /usr/bin/bash -
    readarray -td '' videos < <(
      LC_ALL=C find . \
        -regextype posix-extended \
        -name '.?*' -prune -o \
          -iregex '.*\.(avi|mkv|mp4|vob)' \
          -xtype f \
          -printf '%P\0' |
        sort -z
    )
    
    shopt -u xpg_echo
    play() {
      echo>&2 -E Playing "$@"
      ffplay -hide_banner -infbuf -fs -sn -ast a:0 -- "$@"
    }
    
    case $#videos in
      (0) echo>&2 No video found; exit 1;;
      (1) play "${videos[@]}";;
      (*) echo>&2 Select a video:
          select video in "${videos[@]}"; do
            play "$video" || exit
            break
          done;;
    esac
    

    Algumas outras notas:

    • Você echo -equebraria para nomes de arquivos que contenham \caracteres. Aqui você não deseja que as esequências de escape sejam expandidas, daí o -Efor echoou -rfor print. Se você quiser imprimir uma nova linha extra, adicione-a ao último argumento echoliteralmente ou com $'\n'. Observe também que bash's echosó aceita opções se ou posixnão xpg_echoestiver 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 fazer printf, e o bash só temprintcomo 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 a playfunção pode ser usada para reproduzir mais de um vídeo por vez.
    • Prompts e mensagens do usuário geralmente devem ir para stderr (fd 2). É para onde selectvai a saída, por exemplo.
    • A sintaxe para ler uma linha éIFS= read -r line , não read 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.
    • observe que você *.[mM][kKpP][vV4]também corresponderia a files.mv4(não m4v).
    • 8

relate perguntas

  • Verifique o espaço em disco no Ubuntu (com ls)

  • zsh: "ls -S" não está funcionando na pasta Utilitários

  • Como converter datas de arquivo para um formato específico ao usar 'ls'

  • é canalizado ls o mesmo que ls -1?

  • Como usar a saída de ls para abrir o último arquivo modificado?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve