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. -
readmanipula 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.