Não é possível fazer cd para uma variável (passada) no script bash

Não é possível fazer cd para uma variável (passada) no script bash

Estou usando o bash para obter algumas informações de audacioso a conky para exibição (incluindo a arte do álbum). Eu obtenho o caminho para o diretório do arquivo de música do audacious e, em seguida, tento fazer um cd para esse diretório para encontrar a pasta.jpg - se encontrado, prepare-se para exibição. Infelizmente, não podemos confiar em nomes de caminhos 'bem formados'. Nenhum deles tem problemas no terminal, mas as avaliações que o bash tem ... Ele engasga com espaços duplos ( ) ' / e provavelmente outros, embora a configuração atual pareça funcionar - ok. Aqui está a função relevante:

GetArt ()
{
    file_path=`audtool --current-song-tuple-data file-path` # get the path to the song
    file_path=$(eval echo "${file_path}")                   # pre-expand to full path
    cd "${file_path}"
    if [[ ! -e "folder.jpg" ]];                             # if no art work found
    then
        cp ~/Work/vinyl.png /tmp/cover.png              # put in placeholder
    else
        convert "${file_path}""/folder.jpg" -resize 120x120 /tmp/cover.png # ready for showing
    fi
}

Alguma idéia, ou seria mais fácil pegar a escova de aço e remover a ferrugem do meu compilador 'C'?

Tentei com aspas duplas, aspas simples, crases e até uma construção como:

code=$code \"\$filename\""

mas nada parece funcionar corretamente ainda. Felizmente, ele falha 'muito' porque apenas aparece a foto substituta "não consigo encontrar arte", mas às vezes as coisas arrotam por todo o stderr até a próxima música - ou álbum.

Responder1

Você pode usar file_path="${file_path/#~/$HOME}"para expandirapenaso ~.

Tanto quanto posso dizer,expansão de tilé o único tipo de expansão que precisa ser executada na saída de audtool --current-song-tuple-data file-path. Além disso, apenas um caso específico de notação de til aparece: se o caminho que o Audacious está usando começar com o diretório inicial do usuário que está executando o Audacious, essa parte do caminho será substituída por um ~na saída de audtool. Desde oaudaciouseaudtoolas páginas de manual não esclarecem isso, tentei chegar audtoolaos caminhos de saída prefixados com a ~usernameforma de expansão do til e, felizmente, parece que nunca consegui fazer isso. Digo “felizmente” porque isso significa que a situação é bastante simples.

Como a única transformação que precisa ser feita na saída desse audtoolcomando é substituir um início ~pelo caminho do diretório inicial do usuário, você pode simplesmente escrever um código em seu script que faça essa expansão sozinho e, caso contrário, deixe o caminho inalterado . Você descobriu que os nomes dos arquivos de áudio que você pode reproduzir podem conter caracteres tratados especialmente pelo shell ese você reproduzir arquivos nomeados por outras pessoas,pode até dar origem a uma vulnerabilidade de segurançano seu roteiro. Ao não fazer com que o shell execute - ou mesmo expanda - texto arbitrário e não confiável, você evita esse problema completamente.

Existem várias maneiras de ~se expandir. Eu sugiro:

file_path="$(audtool --current-song-tuple-data file-path)"  # might need tilde expansion
file_path="${file_path/#~/$HOME}"  # do the tilde expansion, if needed

Isso executa manualmente a única transformação que pode ser necessária. Especificamente, quando a saída de audtoolcomeça com ~, isso a substitui pelo diretório inicial do usuário, obtido pela verificação do valor da HOMEvariável. Quando a saída não começa com ~, nenhuma expansão é executada.

Observe que esta abordagem, ${file_path/#~/$HOME}, serianãoestaria correto se fosse usado como uma tentativa de simular todas as formas de expansão do til, porque realizaria substituições incorretas no ~usernameformulário (e em algumas das outras formas mais obscuras). No entanto, desde que os caminhos na saída audtoolusem apenas a notação til no caso simples de designar o diretório inicial do usuário atual - o que acredito ser o caso - então esta abordageméapropriado e correto para esses caminhos.

A maneira como funciona é:

  • Em geral,Bash irá expandir ${parameter/pattern/string}no valor de parameter, mas coma parte que combinapatternsubstituído por string. Se nenhuma peça corresponder ao padrão, o valor exato de parameterserá usado.
  • Quando patterné escrito com um início #, ele só pode ser correspondido começando no início do valor de parameter. (Existem outros caracteres além #dos que são significativos nesta posição: a %exigiria que o padrão fosse correspondido no própriofim, e a /faria com que o padrão fosse correspondido e substituído quantas vezes aparecesse, em vez de no máximo uma vez.)
  • ~não tem nenhum significado especial em um padrão e, portanto, é tratado literalmente, como um caractere a ser combinado e substituído.

Verexpansão de parâmetrospara detalhes.

Observe que o código que escrevi não faz nada para lidar com o caso de audtoolprodução de saída vazia, como acontece quando não há nenhuma música tocando no momento (ou, comoSimon Sudler mencionou, se houver um erro). No entanto, ele não quebra na saída vazia nem atrapalha o manuseio subsequente dela. Então, se você quiser cobrir esse caso, ainda pode.

Por fim, devo mencionar que encobri duas distinções que acredito não serem importantes para o seu caso de uso:

  1. Como audtoolos caminhos do Audacious vêm do Audacious, se você estivesse tentando a situação bizarra de executar o Audacious como um usuário e audtoolcomo outro - e de alguma forma configurou o D-Bus para que funcionasse - então você teria que se preocupar em ~se referir a um diferente diretório inicial do usuário do que o usuário que está executando o script.
  2. Tecnicamente falando, a expansão do til para o usuário atual (que acontece em um shell sozinho ~ou seguida imediatamente por /) não ébastanteequivalente a "$HOME". Os shells podem tentar lidar com o caso estranho onde HOMEnão está definido. Bash tenta lidar com isso e ainda produzir uma expansão correta. Duvido que você se importe com a distinção para esse propósito. Verexpansão de tilpara detalhes.

Responder2

A reatribuição das file_pathvariáveis ​​não é necessária. Existem 2 sinais que podem acontecer, que podem quebrar o script:

  1. A variável está vazia porque audtoolretorna um erro
  2. O audtoolsretorna um diretório, que contém espaços em branco.
  3. audtoolinclui ~para o diretório inicial

Aqui está uma proposta sobre como abordar essas questões:

GetArt ()
{
    file_path="$(audtool --current-song-tuple-data file-path)"
    file_path="$(readlink -f "$(bash -c "echo $file_path")")"
    if [[ ! -d $file_path ]]; then
        echo "error: $file_path does not exists"
        exit 1
    fi
    folder_jpg="$file_path/folder.jpg"
    if [[ ! -e "$folder_jpg" ]]; then
        cp ~/Work/vinyl.png /tmp/cover.png
    else
        convert "$folder_jpg" -resize 120x120 /tmp/cover.png
    fi
}

Manipula "$(command)"os espaços em branco no nome da pasta (se houver). Não use cddentro de um script, se não precisar dele. Verificar se a string de retorno é um diretório é sempre uma boa ideia. Trabalhar com o caminho absoluto é, na maioria dos casos, melhor e evita a execução de comandos na pasta errada.

Notas para a ~expansão no bash:

A expansão do ~é feita pelo bash, então readlink -fnão ajuda aqui. Portanto, a variável que contém ~deve ser executada sem aspas para ser expandida (atualizei o script). É claro que isso pode ser tratado em uma única linha ...

# expansion from current bash
$ set -x; readlink -f ~; set +x
+ readlink -f /home/user
/home/user
+ set +x

# expansion will not work, with quoted ~
$ set -x; readlink -f '~'; set +x
+ readlink -f '~'
/home/user/~
+ set +x

# expansion from un-quoted ~ with sub-shell
$ set -x; readlink -f "$(bash -c "echo ~")"; set +x
++ bash -c 'echo ~'
+ readlink -f /home/user
/home/user
+ set +x

informação relacionada