Removendo caminhos de diretório para obter nomes de arquivos

6

O que eu estou fazendo é converter mp3's com LAME. Eu já tenho um script antigo que eu escrevi que funciona, mas eu quero adicionar a ele essa capacidade - para não mais excluir o arquivo, mas salvá-lo em uma nova pasta raiz com subdiretórios que correspondem ao caminho que já está usando em.

Este é o código que obtive da Internet que estou usando no meu script para obter o caminho:

 c=$FILENAME
 xpath=${c%/*} 
 xbase=${c##*/}
 xfext=${xbase##*.}
 xpref=${xbase%.*}
 path=${xpath}
 pref=${xpref}
 ext=${xfext}

O xpath e path me fornecem a estrutura de diretório /home/user/working-root-directory/band-folder/album-name/

Usando essa técnica, como faço isso para obter apenas a pasta da banda em uma variável separada e a pasta do álbum em uma variável separada?

Então eu posso usá-los para criar novas pastas mantendo todos os mp3s em ordem de álbum de banda para colocá-los em uma pasta raiz diferente; isso me eliminaria de ter que movê-los eu mesmo assim da próxima vez que eu executar o meu script eu não vou re-sample-los novamente porque eles não estarão mais no caminho / pastas directoy de trabalho e ainda ter uma cópia de segurança dos meus arquivos no caso.

    
por uxserx-bw 25.10.2014 / 04:25

5 respostas

7

Ao se referir a $c if por nome_do_arquivo você significa caminho completo para o arquivo, então este trabalho é realmente muito fácil. Existem algumas maneiras de fazer isso.

Usando apenas globs de shell POSIX e expansão de parâmetros, você pode fazer:

c='/home/user/working-root-directory/band-folder/album-name/music-file.mp3'
file=${c##*/}
album=${c#*"${c%/*/"$file"}"/}
band=${c#*"${c%/*/"$album"}"/}
band=${band%%/*} album=${album%%/*}

Basicamente, ele funciona cortando uma string da cauda da variável e, em seguida, cortando os resultados da cabeça da variável. Na última linha, quaisquer restos indesejados da cauda são removidos. Talvez seja mais fácil de entender com dados do mundo real. Se você colocasse o snippet acima em um shell com set -x habilitado, você veria algo nessas linhas impresso em stderr :

+ c=/home/user/working-root-directory/band-folder/album-name/music-file.mp3
+ file=music-file.mp3
+ album=album-name/music-file.mp3
+ band=band-folder/album-name/music-file.mp3
+ band=band-folder
+ album=album-name

Outra maneira de fazer isso é usar o separador de campo interno do shell para dividir o nome do caminho nos limites / .

set -f; IFS=/             #disable globbing so as not to gen more filenames
set -- $c                 #set the shell's arg array to split path
shift "$(($#-3))"         #remove all but relevant fields
band=$1 album=$2 file=$3  #assign values

Aqui estão mais alguns set -x output:

+ c=/home/user/working-root-directory/band-folder/album-name/music-file.mp3
+ set -f
+ IFS=/
+ set -- '' home user working-root-directory band-folder album-name music-file.mp3
+ shift 4
+ band=band-folder
+ album=album-name
+ file=music-file.mp3
    
por 25.10.2014 / 07:03
2

Eu contrataria zsh para esse trabalho:

$ c='/home/user/working-root-directory/band-folder/album-name/filename.mp3'

$ echo $c:h
/home/user/working-root-directory/band-folder/album-name
$ echo $c:h:h
/home/user/working-root-directory/band-folder
$ echo $c:h:h:h
/home/user/working-root-directory

(...)

$ echo $c:t    
filename.mp3
$ echo $c:h:t
album-name
$ echo $c:h:h:t
band-folder

(...)

Se você tiver que usar o bash life é mais difícil, você precisa usar variáveis temporárias:

$ c='/home/user/working-root-directory/band-folder/album-name/filename.mp3'

$ x1=${c%/*}
$ echo $x1
/home/user/working-root-directory/band-folder/album-name
$ x2=${x1%/*}
$ echo $x2
/home/user/working-root-directory/band-folder

 (...)

$ y1=${c##*/}
$ echo $y1
filename.mp3
$ y2=${x1##*/}
$ echo $y2
album-name
$ y3=${x2##*/}
$ echo $y3
band-folder

(...)
    
por 25.10.2014 / 05:42
2

As soluções anteriores parecem muito complicadas para mim. O seguinte parece-me ser a solução mais simples.

Para obter o nome do diretório de uma string de nome de arquivo no bash

 dirname "$varcontainingfilename"

Para obter o APENAS o nome do arquivo de uma string de nome de arquivo no bash use

 basename "$varcontainingfilename"

A partir desta base, você deve conseguir fazer o que quiser com facilidade.

Exemplo de execução deste script de shell como script / a / b / c serviria como um exemplo

 #!/bin/sh
 set -u
 PATH='/bin:/usr/bin'
 export PATH
 filestring="$1"
 fn='basename "$filestring"'
 dn='dirname "$filestring"'
 echo Original File String "$filestring"
 echo Filename is "$fn"
 echo directory is "$dn"
 exit 0
    
por 25.10.2014 / 08:54
2

Para "brincar" com variáveis um pouco mais curtas

c=/home/user/working-root-directory/band-folder/album-name/music-file.mp3
for var in file album band 
do
  eval "$var=\${c##*/}"
  c=${c%\/${!var}}
done

echo $file $album $band
music-file.mp3 album-name band-folder

Outra maneira é usar o comando read

IFS=/ read -r band album file  <<< ${c#"${c%/*/*/*}"/}
    
por 25.10.2014 / 10:38
1

Zsh é uma solução muito mais elegante , mas se não for o seu shell, você pode usar awk :

 printf "%s\n" "$path"
/home/user/working-root-directory/band-folder/album-name/music-file.mp3

band=$(awk -F/ '{print $(NF-2)}' <(printf "%s" "$path"))
printf "%s\n" "$band"
band-folder

album=$(awk -F/ '{print $(NF-1)}' <(printf "%s" "$path"))
printf "%s\n" "$album"
album-name

file=$(awk -F/ '{print $NF}' <(printf "%s" "$path"))
printf "%s\n" "$file"
music-file.mp3
    
por 25.10.2014 / 06:06