Shell Script: Tree

Márcio d'Ávila, 26 de maio de 2004.
Categoria: Unix / Linux

Exemplo de script shell que percorre e exibe uma árvore de diretórios, devidamente indentada. Embora o script seja um exemplo interessante de recursividade, pode se mostrar porém particularmente lento quando lida com diretórios contendo grande quantidade de arquivos.

#!/bin/sh
# Em algumas plataformas, deve-se usar ksh
#
# tree_recursive - Directory tree list
# @author Marcio d'Avila <mhavila_at_inet.com.br>, 2004
#

#
# fn_node_walk
# @param $1 diretorio atual
# @param $2 nivel atual
# @param $3 nivel maximo
#
fn_node_walk()
{
	# Gera o espaco de identacao para o nivel
	INDENT=""
	I=0
	while [ $I -lt $2 ]
	do
		INDENT="  $INDENT"
		I=`expr $I + 1`
	done

	# Exibe a identacao e o nome do diretorio
	# Em algumas versoes de shell, o comando deve ser:
	# echo -n "$INDENT$1"
	echo "$INDENT$1\c"

	# Se link simbolico, indica e finaliza
	if [ -L "$1" ]; then
		echo " [link]"
		return
	fi

	# Se atingido nivel maximo, finaliza
	if [ $2 -ge $3 ]; then
		echo ""
		return
	fi

	# Navega para proximo nivel (sub-diretorios)
	# Caso nao haja permissao suficiente, indica e finaliza
	if cd "$1" 2> /dev/null && [ -r . ]; then
		echo ""
	else
		echo " [permission denied]"
		return
	fi

	# Lista o conteudo do diretorio, filtrando apenas
	# sub-diretorios e links, e os percorre recursivamente
	ls -F 2> /dev/null | grep '[/@]$' | sed 's/.$//' |
	while read NODE
	do
		fn_node_walk "$NODE" `expr $2 + 1` $3
	done
	cd ..
}

fn_syntax()
{
	echo "`basename $0` [ -m <max_depth> ] [ <initial_dir> ]"
	exit 1
}


########## MAIN ##########

# Trata possivel parametro: -m max_nivel
MAX_DEPTH=999
while getopts "m:" OP 2> /dev/null
do
	case $OP in
		m) MAX_DEPTH=$OPTARG ;;
		*) fn_syntax ;;
	esac
done
test $OPTIND -gt 1 && shift `expr $OPTIND - 1`
test $# -le 1 || fn_syntax

# Trata possivel parametro: dir_inicial
if [ $# -eq 1 ]
	then ROOT=$1
	else ROOT=.
fi

# Inicia navegacao recursiva de diretorios
fn_node_walk "$ROOT" 0 $MAX_DEPTH

exit 0
# end

Já o script a seguir apresenta uma abordagem bem mais direta. Aproveitando a capacidade do comando find em localizar apenas diretórios (-type d), ele simplesmente trata a saída do find para exibir espaços de indentação ao invés do caminho de cada diretório. Portanto, afora o tratamento de parâmetros, a ação consiste efetivamente de apenas 2 comandos em um pipe.

A opção de limitar a profundidade da pesquisa também é convenientemente já implementada pela opção maxdepth do comando find. Esta opção está disponível no GNU find, porém não existe em algumas outras implementações, como no Solaris.

#!/bin/sh
#
# tree - Directory tree list
# @author Marcio d'Avila <mhavila_at_inet.com.br>, 2004
#

fn_syntax()
{
	echo "`basename $0` [ -m <max_depth> ] [ <initial_dir> ]"
	exit 1
}


########## MAIN ##########

# Trata possivel parametro: -m max_nivel
MAX_DEPTH=999
while getopts "m:" OP 2> /dev/null
do
	case $OP in
		m) MAX_DEPTH=$OPTARG ;;
		*) fn_syntax ;;
	esac
done
test $OPTIND -gt 1 && shift `expr $OPTIND - 1`
test $# -le 1 || fn_syntax

# Trata possivel parametro: dir_inicial
if [ $# -eq 1 ]
	then ROOT=$1
	else ROOT=.
fi

# O parametro -maxdepth existe no GNU find
# Pode nao estar disponivel em outras implementacoes
find "$ROOT" -maxdepth $MAX_DEPTH -type d 2> /dev/null | sed 's/[^/]*\//  /g'

exit 0
# end

Creative Commons License

© 2003-2007, Márcio d'Ávila, mhavila.com.br, direitos reservados. O texto e código-fonte apresentados podem ser referenciados, distribuídos e utilizados, desde que expressamente citada esta fonte e o crédito do(s) autor(es). A informação aqui apresentada, apesar de todo o esforço para garantir sua precisão e correção, é oferecida "como está", sem quaisquer garantias explícitas ou implícitas decorrentes de sua utilização ou suas conseqüências diretas e indiretas.