Shell Script para executar script de shell para todos os subdiretórios

3

Estou fazendo um script para simplificar minhas tarefas diárias. Todos os dias, tenho que procurar algumas coisas dentro de um servidor da empresa. Tudo bem, no entanto, agora, eles segregaram cada objeto em sub-diretórios. Eu estou procurando uma solução na qual meu script de shell existente será executado repetidamente em cada sub diretório dentro de um determinado diretório. Como eu faço isso? Eu sou muito novo no Linux e ainda estou aprendendo as coisas.

Aqui está meu script:

#!/bin/bash
MainDir=/path/to/dir/containing/subdirs
# cd into dir
cd $MainDir

for dir in $(ls); do

#fetch start time of uut
grep -i "01_node_setup" $dir/his_file | tail -1 >> /home/xtee/sst-logs.out

#check if sysconfig.out exists
if [ -f $dir/sysconfig.out];
then
    grep -A 1 "Drive Model" $dir/sysconfig.out | tail -1 >> /home/xtee/sst-logs.out
else
    grep -m 1 "Pair0 DIMM0" $dir/node0/trans_file_prev/*setupsys* | tail -1 >> /home/xtee/sst-logs.out
fi

done

#cd back to where we started
cd $OLDPWD

Um cara legal me ajudou com o roteiro, e o roteiro acima é o que saiu. No entanto, funcionou bem, o arquivo sst-logs.out exibe binary file /some/subdirectory/ em vez da saída do grep. O que está errado no roteiro?

    
por JudeJitsu 02.08.2012 / 11:54

4 respostas

4

encontrar salvará você:

find /your/dir/with/subdirs -type d -exec sh -c 'cd "{}" ; /path/to/your/script.sh ;' \;
    
por 02.08.2012 / 12:06
3

Existem vários problemas no seu script.

cd $MainDir

Melhor faça isso cd "$MainDir" . Aqui isso não é importante, mas é um bom hábito entrar. Se você deixar uma expansão variável sem aspas, o valor da variável será dividido em palavras e cada palavra será tratada como um padrão curinga da shell; Portanto, esse comando falharia se $MainDir contivesse espaço em branco ou \[?* . Colocar as aspas duplas nunca dói (a menos que você queira que a divisão e a correspondência de nome de arquivo ocorram) e evita essas expansões extras. O mesmo vale para substituições de comandos ( $(somecommand) ). Sempre coloque aspas duplas em torno das substituições de variáveis e comandos , a menos que você saiba que deseja dividir e corresponder a nomes de arquivos.

for dir in $(ls); do

Não analise a saída de ls . Você quase nunca precisa de ls em scripts. Conforme explicado acima, o resultado de uma substituição de comando é dividido em palavras tratadas como padrões de caractere curinga, portanto, $(ls) manipula espaços em branco e caracteres curinga, além da distorção de caracteres não imprimíveis que ls pode fazer. Listar os nomes dos arquivos em um diretório é construído no shell:

for dir in *; do

Se você fizer isso for dir in */; do , apenas os subdiretórios do diretório atual serão correspondidos, e não outros tipos de arquivos.

if [ -f $dir/sysconfig.out];

Você precisa de espaços em branco em cada lado dos colchetes, exceto quando o caractere próximo a ele for um caractere de pontuação do shell: ();&|<> . E, novamente, coloque aspas duplas em torno das substituições de variáveis (isso vale para todos os outros lugares onde você tem uma substituição de variável): if [ -f "$dir/sysconfig.out" ];

#cd back to where we started
cd $OLDPWD

Isso é inútil: o processo está prestes a sair, alterar seu diretório atual não afetará nada. Observe que cada processo possui seu próprio diretório atual: alterá-lo em um script não afeta o programa que chamou o script.

Mudando para o motivo que você fez esta pergunta, não está claro o que você quer. " binary file /some/subdirectory/ " não faz muito sentido: você não receberia essa mensagem com um diretório. Para melhor ajuda, copie e cole a mensagem de erro. Você deve sempre copiar e colar mensagens de erro quando solicitar ajuda on-line.

A partir da sua descrição, parece que os arquivos moveram um nível de diretório mais profundamente. Se for esse o caso, altere a linha for dir in */; do para

for dir in */*/; do
    
por 03.08.2012 / 02:32
1

Existem várias maneiras de fazer isso. você pode executar seu script existente em um loop for, ou usar find e xargs, ou talvez até mesmo usar a opção -r aka --recursive do grep.

O mais simples é provavelmente escrever um wrapper for loop em torno do seu script existente. Por exemplo:

#! /bin/bash
cd /path/to/top/level/directory

for d in */ ; do 
  pushd $d
  # call your script here
  popd
done
    
por 02.08.2012 / 12:03
0

Uma ligeira melhoria na sugestão de find do @ rush, em vez de usar a opção -exec , pode evitar adicionar o comando cd ao fazer algo como isto:

find /path/to/dir/containing/subdirs -type d -execdir /path/to/your/script.sh \;

Dessa forma, você pode evitar completamente o loop for em seu script original.

    
por 01.02.2016 / 20:43