Construindo caminhos robustamente

16

Digamos que eu tenha várias variáveis em um script de shell (por exemplo, em zsh):

FOLDER_1, FOLDER_2, etc.

Estas variáveis referem-se a pastas descendentes de / . Por exemplo, se eu tiver um caminho /home/me/stuff/items

as variáveis seriam:

FOLDER_1='home'
FOLDER_2='me'
FOLDER_3='stuff'

Agora, digamos que quero reconstruir o caminho correspondente concatenando as variáveis. Uma maneira possível é construir o caminho da seguinte forma:

PATH=$FOLDER_1/$FOLDER_2/$FOLDER_3/

No entanto, digamos que algumas das variáveis FOLDER_i vêm com barras à direita, enquanto outras não (e não sabemos qual), por exemplo,

FOLDER_1='home'
FOLDER_2='stuff/'
FOLDER_3='items'

Minha pergunta é: Como eu poderia construir o caminho de maneira robusta? (por exemplo, evitando barras duplas e adicionando-as onde elas precisam estar).

Eu pensei que uma maneira de fazer isso é adicionar o / sempre entre pares de variáveis e, em seguida, excluir quaisquer duplicatas com sed , mas não posso fazê-lo funcionar (não tenho certeza se estou lidando / corretamente em sed ).

Além disso, estou reinventando a roda ? (ou seja, existe algum built-in que já faz isso?).

Finamente, se as variáveis estiverem em um array , por exemplo FOLDERS , seria possível fazer isso sem loop? (ou alternativamente, por looping, mas sem saber quantos FOLDERS existem na matriz).

    
por Amelio Vazquez-Reina 24.10.2011 / 20:42

4 respostas

12

Você pode usar printf com uma matriz:

parts=("$FOLDER_1" "$FOLDER_2" "$FOLDER_3");
printf '/%s' "${parts[@]%/}"
# Use "printf -v path" to save it into a variable called "path" instead of printing it

O operador % apara as sequências à direita, neste caso / . Ao aplicá-lo a parts[@] , ele corta cada membro da matriz separadamente.

A chave para entender esse truque printf é esse bit de man 1 printf : "A string de formatação é reutilizada sempre que necessário para satisfazer os argumentos."

    
por 24.10.2011 / 21:07
11

A resposta simples é parar de se preocupar e adorar várias barras. Várias barras têm o mesmo efeito que uma barra única (exceto que um caminho que começa com // tem um significado diferente em alguns sistemas; as camadas de emulação unix no Windows são as únicas que posso nomear). Isso é por design, e ser capaz de montar nomes de arquivos sem ter que se preocupar com várias barras era uma parte importante dessa decisão de design.

Para unir elementos de matriz, em zsh, é possível usar a expansão de parâmetro j bandeira .

dir=${(j:/:)FOLDERS}

Você pode esmagar as barras duplicadas enquanto estiver nela, mas isso é puramente estético.

setopt extended_glob
dir=${${(j:/:)FOLDERS}//\/\/##/\/}

Em ksh e bash, você pode unir uma matriz usando o primeiro caractere de $IFS como separador. Você pode então esmagar as barras duplicadas. No bash, você precisará fazer shopt -s extglob para ativar os ksh globs na última linha do snippet abaixo.

IFS=/
dir="${FOLDERS[*]}"
unset IFS
dir=${dir//\/+(\/)//}
    
por 25.10.2011 / 02:13
3

Como o sed não funciona para você? Tente sed 's|/\+|/|g' após a concatenação ou sed 's|/||g' antes.

    
por 24.10.2011 / 21:00
1

bash 4 introduziu globbing estendido, que permite a correspondência de expressão regular na substituição de parâmetro ${var....} ... Ele é desativado por padrão. Para habilitá-lo para o seu script, basta definir a opção de shell extglob ...

Supondo que $ dir == /home/me/////////stuff//items

shopt -s extglob; dir="${dir//+(\/)//}"

Valor resultante de $ dir

/home/me/stuff/items  

Aqui estão alguns exemplos com do-s e-não-s - Bash Extended Globbing

    
por 24.10.2011 / 21:46