Usando df e tentando awk uma coluna específica

1

Entre outros problemas com este script que estou tentando fazer (este é o primeiro script unix / linux que já fiz), estou tentando usar df para obter o% de espaço em disco usado e enviá-lo por e-mail para a raiz. Nossas instruções foram para excluir o / proc disquete e cdrom de df também.

O que eu tenho até agora:

fsExclude=(/proc /dev/floppy /dev/cdrom) #Exclusions from df file system
fsUsed=15 #percent to watch for
WarnEmail=root #email for warning message
if (df -x $fsExclude | awk '$5' | sed '2p' > fsUsed)
then
df -h > dfFile.tmp
mail -s "WARNING: Almost out of disk space %" '$WarnEmail' < dfFile.tmp
rm dfFile.tmp
fi

Agora eu sei que há algumas coisas erradas com isso. Quando eu o executo apenas para ver que tipo de saída eu recebo, recebo (a primeira linha era uma mensagem acima da declaração if que eu não incluí acima):

Emailing admin, disk almost full...
3 
$WarnEmail... User unknown 
60 
awk:    cmd. line:1: print $4 
awk: cmd. line:1: ^ parse error    
/root/dead.letter... Saved message in /root/dead.letter 
…

Há mais, mas vou guardar isso para mais tarde. Eu enviei a raiz para fora do script de maneira semelhante e não tive problemas, mas, enquanto no script, ele não quer funcionar. Com o awk da saída df, eu só quero pegar o valor da coluna% usada para ver se é maior ou menor que o valor fsUsed. Se estiver, entre e envie por e-mail para a raiz toda a saída do df. Eu tenho visto, enquanto pesquisando algo, que alguém sugeriu usar algo que tivesse um -perc ou -avail, mas que nem funcionava aqui. Isso me diria que eram desconhecidos, então eu tentei voltar ao awk.

Qualquer ajuda para consertar isso seria muito apreciada.

    
por Jeremy 21.06.2015 / 18:38

2 respostas

1

Os principais problemas que você tem aqui são

  1. fsExclude é uma matriz, para obter todos os elementos, você precisa de ${array[@]} . Em qualquer caso, a opção -x precisa de tipos de sistemas de arquivos, não de dispositivos.

  2. Um erro de sintaxe no seu comando awk , você queria

    awk '{print $5}' 
    

    Sem o print , awk terá a expressão $5 que avalia para true se existir um campo 5 e, portanto, imprimirá todas as linhas com pelo menos 5 campos.

  3. Se eu entendi seu objetivo, parece que você deseja comparar a porcentagem atual com o valor de fsUsed . No entanto, seu comando cria um arquivo chamado fsUsed e imprime a saída de df . O que você queria era

    if [ "$(df -x $fsExclude | awk '$5' | sed '2p')" -gt "$fsUsed" ]
    

    O $() é chamado de substituição de comando e é expandido para o saída de qualquer comando que você executou. Isso é o que você quer comparar com o valor de fsUsed e, para obter esse valor, você precisa do $ .

  4. Você tem $WarnEMail entre aspas simples, isso significa que está sendo tratado como uma string literal e não como uma variável. Tente isso:

    mail -s "WARNING: Almost out of disk space %" "$WarnEmail" < dfFile.tmp
    
  5. Seu comando df retornará várias linhas, mas você está executando uma única comparação, que não funcionará. Você precisará verificar cada linha da saída de df :

Então, você também está fazendo isso de uma maneira desnecessariamente complexa. Por que não algo assim:

#!/bin/bash
fsExclude="/proc|/dev/floppy|/dev/cdrom" #Exclusions from df file system
fsUsed=15 #percent to watch for
WarnEmail=root #email for warning message
problem=0;
df | grep -v "$fsExclude" |
    while read line
    do
    ## Check the percentage, send the mail if at least
    ## one mount point's percentage is > $fsUsed
    if [[ $(grep -oE '[0-9]+%' <<<"$line" | tr -d '%') -gt $fsUsed ]]
    then
        ## I'm not sure if 'command | mail' works and I don't have a system
        ## I can test it on. If it doesn't, use a file as you did before. 
        df -h | mail -s "WARNING: Almost out of disk space %" "$WarnEmail" 
        ## No need to rpocess any more lines, exit the while loop
        break;
    fi
    done
    
por 21.06.2015 / 19:38
0

Os showstoppers:

  • Você está executando o comando df -x /proc /dev/floppy /dev/cdrom . Isso diz a df para pular os sistemas de arquivos do tipo /proc , que não existem (o tipo de sistema de arquivos seria proc ), e listar apenas /dev/floppy e /dev/cdrom . Não há opção de omitir dispositivos específicos, você pode filtrá-los.

  • Para imprimir o quinto campo no awk, use awk '{print $5}' : isso executa a instrução print $5 em cada linha. awk '$5' imprime a linha inteira se o quinto campo não for zero ou vazio ( $5 é uma condição; já que não há ação correspondente, a ação padrão é executada e a linha inteira é impressa). awk 'print $5' é um erro de sintaxe.

  • Em sed '2p' > fsUsed , o sinal > é um operador de redirecionamento: a saída do comando sed é gravada em um arquivo temporário fsUsed .

  • '$WarnEmail' é uma string literal, consistindo de 10 caracteres começando com um sinal de dólar. Para expandir a referência de variável, use aspas duplas.

Além disso:

  • Não use um arquivo temporário para armazenar alguma saída pequena. Use substituição de comando para colocá-lo em uma variável.

  • Passe a opção -P para df ao analisar sua saída. Caso contrário, poderá adicionar novas linhas no meio de um registro quando o caminho do dispositivo for muito longo.

  • Você pode fazer toda a sua filtragem no awk.

Aqui está outra maneira de escrever seu script que amalgama os e-mails em um só.

body=$(df -P | awk -v fsUsed=15 fsExclude='/dev/floppy /dev/cdrom' '
    BEGIN {split(fsExclude, fsExcludeArray)}
    NR == 1 {next}           # skip the header line
    $1 in fsExcludeArray {next}
    {$5 = sub(/%/, "")}      # remove the % character from the Use% column
    $5 > fsUsed {print}      # print lines with almost-full disks
')
if [ -n "$body" ]; then
  # $body is non-empty: there is at least one almost-full filesystem
  echo "$body" | mail -s "Warning: some filesystems are almost full" "$WarnEmail"
fi
    
por 23.06.2015 / 02:26