A maneira de listar todos os arquivos em um diretório no shell é simplesmente *
.
for f in *; do …
Em shells com suporte à matriz (bash, ksh, zsh), você pode atribuir diretamente a lista de arquivos a uma variável de matriz: fs=(*)
Isso omite arquivos de ponto, o que vai contra o uso de ls -A
. No bash, defina a opção dotglob
primeiro para incluir arquivos de pontos e defina nullglob
para ter uma matriz vazia se o diretório atual estiver vazio:
shopt -s dotglob nullglob
fs=(*)
Em ksh, use FIGNORE=".?(.)"; fs=(~(N)*)
. Em zsh, use os qualificadores D
e N
glob: fs=(*(DN))
. Em outras conchas, isso é mais difícil; sua melhor aposta é incluir cada um dos padrões *
(arquivos não pontuais), .[!.]*
(arquivos de ponto único, não incluindo .
e arquivos de ponto duplo) e ..?*
(arquivos de ponto duplo, não incluindo ..
em si) e verifique se há vazio.
set -- *; [ -e "$1" ] || shift
set .[!.]* "$@"; [ -e "$1" ] || shift
set ..?* "$@"; [ -e "$1" ] || shift
for x; do … # short for for x in "$@"; do …
Eu explicaria melhor o que estava errado em sua tentativa também. O principal problema é que cada lado de um canal é executado em um subprocesso, portanto, as atribuições para fs
no loop estão ocorrendo em um subprocesso e nunca são passadas para o processo pai. (Esse é o caso na maioria dos shells, incluindo bash; as duas exceções são ATT ksh e zsh, onde o lado direito de um pipeline é executado no shell pai.) Você pode observar isso ativando um subprocesso externo e organizando-o para imprimir o ID do processo dos seus pais¹¹²:
sh -c 'echo parent: $PPID'
{ sh -c 'echo left: $PPID >/dev/tty'; echo $? >/dev/null; } |
{ sh -c 'echo right: $PPID >/dev/tty'; echo $? >/dev/null; }
Além disso, seu código teve dois problemas de confiabilidade:
- Não analise a saída de
ls
. -
read
manipula espaços em branco e barras invertidas; para analisar linhas, você precisa dewhile IFS= read -r line; do …
Para os momentos em que você precisa analisar linhas e usar o resultado, coloque todo o processamento de dados em um bloco.
producer … | {
while IFS= read -r line; do
…
done
consumer
}
Note que $$
não mostra nada: é o ID do processo principal do shell, ele não muda em subshells.
²
Em algumas versões bash, se você chamar apenas sh
em um lado do canal, poderá ver o mesmo ID do processo, porque o bash otimiza uma chamada para um processo externo. O fluff com as chaves e echo $?
anulam essa otimização.