ksh loop: “para dir in find .. do” não funciona, ao contrário de “for dir in ls .. do”

0

Ambas as linhas a seguir retornam a lista de diretórios de um dos meus diretórios.

O primeiro deles usa um padrão de nome, enquanto eu preciso escolher dirs, pois eles realmente são diretórios para processá-los em um loop. Eu gostaria, portanto, de usar o segundo:

ls -l  | awk '{print $9}' | grep 'dirsPrefix*'

find . -maxdepth 1 -type d | grep -v \.$ | awk -F'./' '{print $2}'

Mas dentro de um ksh para loop, o primeiro está funcionando ao contrário do segundo ... Por quê ? :

(solução alternativa:

for dir in 'find . -maxdepth 1 -type d -exec echo "{}" \; | awk -F'/' {print $2}'
do 
  echo "dir: $dir"
done

funcionará)

Isso também funciona:

for dir in 'ls -l  | awk '{print $9}' | grep 'dirsPrefix*''
do 
  echo "dir: $dir"
done

Mas isso não acontece:

for dir in 'find . -maxdepth 1 -type d | grep -v \.$ | awk -F'./' '{print $2}''
do 
  echo "dir: $dir"
done
    
por user1767316 09.08.2017 / 14:25

4 respostas

4

Você está tentando muito difícil obter os diretórios no diretório atual. Tudo o que você precisa fazer é:

for dir in */; do echo "dir: $dir"; done
# .........^^

Se você quiser armazená-los em uma matriz:

dirs=( */ )
    
por 09.08.2017 / 15:03
1

Altere para isto:

for dir in $(find . -maxdepth 1 -type d | grep -v \.$ | awk -F'./' '{print $2}')
do 
  echo "dir: $dir"
done

Não sei explicar por que funciona, mas sei que você deve usar $() sobre backticks.

    
por 09.08.2017 / 14:29
1

Você precisa perceber que o comando que está executando, por exemplo,

for dir in 'find . -maxdepth 1 -type d | grep -v \.$ | awk -F'./' '{print $2}''

existem 2 níveis de interpretação de citações. No primeiro nível, isto é, no nível da linha de comando, onde o comando é emitido, o texto sob os backquotes '....' é primeiro varrido para barras invertidas e $ variáveis, assim como em uma interpolação de aspas duplas. Já que $ está solitário no final, então não será expandido. Não há mal em escapar disso.

Então, isso deve deixar esse grep -v \.$ ----> grep -v \.$

Agora, após o término deste passo, ele será entregue a um subshell para execução. E nessa sub-linha, o comando grep -v \.$ é analisado e a barra invertida é removida, então o que grep executável obtém no final desta fase é: grep -v .$

Agora, todas as linhas não-vazias corresponderão a esse padrão e encontrarão todas as linhas não-vazias geradas, pela simples razão de que os nomes dos arquivos não devem ser não-vazios.

Então, isso significa que todos os outputs de find serão selecionados e, portanto, o inverso disso implica que nenhuma saída de find deve ser selecionada. Então o awk está todo vestido, mas não tem para onde ir.

Solução:

Há muitas coisas que você pode fazer para corrigir o problema.

  • Adicione mais uma barra invertida ao grep, tornando-a: grep -v \\.$ Com base no que acontece em cada etapa da expansão de cotação para este cenário, convença-se de que essa correção funciona.
  • Use a forma $ () de interpolação de comando, pois neste formato a cotação começa de novo dentro do $ () ao contrário da forma de '' backquoting ''.
  • Use aspas simples no grep, tornando-o: grep -v '\.$'
  • Use classes de caractere para escapar do. : grep -v '[.]$'
  • Faça tudo no comando find :
find . -maxdepth 1 -type d ! -name . -exec sh -c '
   for d do printf "dir: %s\n" "${d:2}"; done
' sh {} +
    
por 09.08.2017 / 16:30
0

Existe um problema com a expressão grep . Ele corresponderá a todos os nomes de diretório que terminem com . , mas também parece distorcer a saída de alguma forma para tornar for confuso. Há muitas coisas que você pode fazer sobre isso.

  • Alterar a expressão do grep para grep -v "^\.$" provavelmente será mais correto (pois corresponderá apenas ao diretório . ) e funcionará no seu for -loop

  • Como já foi apontado por @Jesse_b, é melhor, por vários motivos, usar a expressão $(..) para execução. Isso resolverá seu problema imediato, mas não corrigirá o possível bug.

  • Você pode usar find até o final, tornando este script um pouco mais simples:

    for dir in 'find . -maxdepth 1 -type d ! -name "." -printf "%f "'
    do
       echo $dir
    done
    

Não é provável que todas essas soluções sejam problemáticas se houver diretórios com espaços ( ) em seus nomes.

    
por 09.08.2017 / 15:09