Identifica a pasta no bash

1

Eu estava tentando aprender como identificar apenas pastas dentro de uma pasta no nível principal. exemplo:

  • main
  • -pasta 1
  • -pasta 2
  • -pasta 3

Eu comecei com este script:

#!/bin/bash

LOCATION="/mnt/test/build/"

for folder in $(ls $LOCATION); do

    echo "$folder"
done

No entanto, quando executo o script, ele faz eco do conteúdo inteiro e, se uma pasta tiver um espaço, o nome será adicionado a duas linhas. Se eu alterar a linha de eco de "$folder" para '$folder' , ela será apenas uma pasta de eco. Qualquer artigo sugestivo seria ótimo também.

    
por DᴀʀᴛʜVᴀᴅᴇʀ 13.12.2012 / 16:20

5 respostas

2

Não use ls para simplesmente iterar pelo conteúdo de um diretório, use globbing:

#!/bin/bash
LOCATION="/mnt/test/build/"
for folder in "$LOCATION"/*; do
    [ -d "$folder" ] || continue
    echo "$folder"
done

O comando [ -d "$folder" ] testa se $folder é um diretório ou não. Se não estiver, a entrada será ignorada com continue . Observe as aspas em torno de $LOCATION e $folder , que impedem que o script quebre quando $LOCATION contém espaço em branco.

Se você realmente precisa processar o conteúdo de ls , use algo como:

ls "$LOCATION" | while read folder; do
    echo "$folder"
done

Se você tem a restrição adicional de que as variáveis de dentro do loop precisam ser acessadas após o loop, use a substituição do processo do Bashs:

while read folder; do
    echo "$folder"
done < <(ls "$LOCATION")

O manual do Bash está disponível no link .

    
por 13.12.2012 / 17:15
2

Não analise a saída de ls . Você não precisa do ls para listar o conteúdo de um diretório: você pode usar curingas do shell.

Quando você escreve $(ls $LOCATION) , a saída do comando ls é dividida em palavras separadas onde quer que haja espaço em branco. É por isso que seu comando desconfiou nomes de arquivos com espaços. Você pode modificar a variável IFS para evitar que os espaços sejam considerados separadores, mas não há como distinguir entre uma nova linha que separa nomes de arquivos de uma nova linha em um nome de arquivo, portanto não é possível evitar completamente o problema. Além disso, cada palavra resultante da divisão é tratada como glob (ou seja, um padrão de caractere curinga) e substituída pela lista de arquivos correspondentes, se houver. Uma regra simples de script de shell é: sempre coloca aspas duplas em torno das substituições de variáveis "$foo" e substituições de comandos "$(foo)" . As aspas duplas impedem a divisão e globbing.

O snippet a seguir é equivalente ao seu loop, exceto pelo fato de não manchar os nomes dos arquivos e imprimir o caminho completo para cada arquivo.

for x in "$LOCATION"/*; do
  echo "$x"
done

Se você quiser o caminho relativo a $LOCATION , uma maneira é mudar primeiro para o diretório de destino.

cd "$LOCATION"
for x in *; do
  echo "$x"
done

Outra maneira é remover o prefixo do nome do arquivo.

for full_path in "$LOCATION"/*; do
  relative_name=${full_path#"$LOCATION/"}
  echo "$relative_name"
done

Imprime o nome de todos os arquivos no diretório de destino. Se você quiser apenas listar subdiretórios (incluindo links simbólicos para diretórios), adicione um / ao padrão glob para restringir as correspondências.

for full_path in "$LOCATION"/*/; do
  relative_name=${full_path#"$LOCATION/"}
  relative_name=${relative_name%/}
  echo "$relative_name"
done

Se você não quiser que os links simbólicos sejam incluídos, faça um teste explícito para um diretório dentro do loop.

for full_path in "$LOCATION"/*/; do
  if ! [ -d "$full_path" ]; then continue; fi
  relative_name=${full_path#"$LOCATION/"}
  relative_name=${relative_name%/}
  echo "$relative_name"
done
    
por 14.12.2012 / 01:16
0

Para encontrar todos os diretórios abaixo do nível em que você está

find . -type d

se você quiser se limitar a um nível

find . -type d -maxdepth 1 -mindepth 1

Editar

Eu perdi parte da sua pergunta:

SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for dir in $( find . -type d -maxdepth 1 -mindepth 1 ) ; do
  echo ${dir}
done
IFS=$SAVEIFS

Mas dependendo do que você deseja fazer, você também pode usar a opção -exec de find para executar um comando em cada arquivo.

    
por 13.12.2012 / 16:39
0

Para evitar o problema de nome com espaço, você pode usar um tempo com uma condição read . read lerá a linha completa, incluindo qualquer espaço intermediário.

Para selecionar apenas o diretório, você deve adicionar um novo teste usando -d .

#!/bin/bash
LOCATION="/home/giuseppe"
ls -1 $LOCATION | while read folder; do
  [ -d "$folder" ] && echo "$folder"
done
    
por 13.12.2012 / 17:23
0

Este comando encontrará todos os diretórios somente diretamente em $ LOCATION. Não irá listar qualquer conteúdo dos referidos diretórios.

#!/bin/bash
LOCATION="/mnt/test/build/"

find "$LOCATION" -mindepth 1 -maxdepth 1 -type d

Se você deseja imprimir apenas os caminhos relativos e não absolutos, use isto:

find "$LOCATION" -mindepth 1 -maxdepth 1 -type d -printf "%f\n"
    
por 14.12.2012 / 02:10

Tags