Obter valores de uma seção de um arquivo

7

Eu tenho um arquivo de configuração no seguinte formato.

<Title>
 [part1]
  A.File = a
  A.Val = val1
  B.File = a
  B.Val = val1
 [part2]
  A.File = a1
  A.Val = val2 
  B.File = a
  B.Val = val1

Eu quero extrair valores apenas da primeira parte.

 #!/bin/sh 
getCalibDate()
{
 file="/path/of/config/file"
 value='cat ${file} | grep Val | cut -d'=' -f2'
    for v in $value
    do
            echo $v
    done
}
getCalibDate

O script acima retornará todos os valores. Como posso obter valores apenas da primeira parte (part1)?

    
por user3153014 22.08.2014 / 13:22

6 respostas

8

Se você tiver apenas 4 linhas após [part1] , poderá usar a opção -A4 com grep :

cat ${file} | grep -A4 "part1" | cut -d'=' -f2'

Para casos gerais (mais de 4 linhas depois de [part1]), use sed para obter o texto entre duas partes:

cat ${file} | sed -n "/part1/,/part2/p" | head -n-1

head é para excluir part2 adicional no final

Como terdon disse que você não precisa usar cat , você pode fazer o seguinte:

grep -A4 "part1" ${file} | cut -d'=' -f2'

OR:

sed -n "/part1/,/part2/p" ${file} | head -n-1
    
por 22.08.2014 / 13:42
4

Você precisa usar uma ferramenta mais sofisticada para analisar o arquivo. Por exemplo, awk :

#!/bin/sh 

getCalibDate()
{
 file="${1}"
 value=$(awk  '/\[part/{a++}(a<2 && /Val/){print $NF}' ${file})

    for v in $value
    do
            echo $v
    done
}

getCalibDate ${1}

Aqui, a variável a é incrementada toda vez que uma linha corresponde a [part . Em seguida, o último campo ( $NF ) é impresso quando uma linha corresponde a Val , mas somente se a for menor que 2, somente se estivermos na primeira seção.

    
por 22.08.2014 / 13:46
2

e use isso:

sed -n -e '/\[part1\]/,/\[part2\]/p' FILE |sed -e '1d;$d'| awk -F "=" '{print $2}'

OUTPUT é:

 a
 val1
 a
 val1
    
por 22.08.2014 / 13:54
2

Para obter as linhas inteiras da primeira parte:

awk '$1 ~ /^\[/ {n++;next} n==1'

Para imprimir apenas o lado direito do primeiro = :

awk '$1 ~ /^\[/ {n++;next} n==1 {sub(/^[^=]*=[[:blank:]]*/,""); print}'
    
por 22.08.2014 / 14:34
2

Há algumas boas respostas aqui, mas vejo apenas um que incorpora a parte Val do problema, e é ambíguo se isso está correto. Concordo que awk é "uma ferramenta incrível", mas não é necessário aqui; Eu acredito que este comando sed :

sed -n '/\[part1\]/,/\[part2\]/s/.*Val.*=//p' "$file"

provavelmente faz o que é desejado. Como as outras soluções sed -e '/\[part1\]/,/\[part2\]/p' ( Networker e Babyy ), isso é trivialmente adaptável para selecionar qualquer seção. (Você precisa, é claro, saber o nome dele; se você conhece apenas o seu número ordinal, você pode adaptar a resposta de terdon ou resposta de glenn jackman , Ambas as seções contam , em vez de procurar um nome específico. Se você não sabe o nome da seção seguinte, você pode fazer

sed -n '/\[part42\]/,/\[part/s…' "$file"

por exemplo.

Minha única meta pergunta é sobre a parte cut -d'=' -f2 da pergunta. Se uma linha de entrada da qual estamos extraindo dados contiver vários caracteres = depois de Val (ou seja, o valor do campo contém = caractere (s)), por exemplo,

Einstein.Val = E=mc^2

, o comando cut acima extrairá apenas o texto entre o primeiro e o segundo = (isto é, o valor do campo, até (mas não incluindo) o primeiro = ), por exemplo,  E . O comando sed que eu apresentei acima extrairá apenas o texto após o último = (por exemplo, mc^2 ). Para obter tudo após o primeiro = (por exemplo, E=mc^2 ), use

sed -n '/\[part1\]/,/\[part2\]/s/.*Val[^=]*=//p' "$file"

Para imitar o comportamento do cut (por exemplo,  E ), use

sed -n '/\[part1\]/,/\[part2\]/s/.*Val[^=]*=\([^=]*\).*//p' "$file"

Observe que minha abordagem pressupõe que os dados parecem pelo menos geralmente como a ilustração na pergunta; Ou seja, pelo menos um = aparece em algum lugar à direita da string Val . Assim, todas as minhas soluções irão ignorar a entrada como

Girl.Name = Valerie
Valerie Bertinelli

mesmo se estiver entre [part1] e [part2] .

    
por 22.08.2014 / 17:33
0
sed -n '/part2/q;s/[^=]*=//p' \
<<\DATA
<Title>
 [part1]
  A.File = a
  A.Val = val1
  B.File = a
  B.Val = val1
 [part2]
  A.File = a1
  A.Val = val2
  B.File = a
  B.Val = val1
DATA

OUTPUT

 a
 val1
 a
 val1

Isso deve fazer o truque. Ele irá imediatamente q uit o arquivo de entrada na primeira vez que encontrar a string part2 em qualquer lugar na entrada. Isso significa que ele nunca tenta ler as partes do arquivo que você não quer - o que deve torná-lo muito eficiente.

O -n desativa a impressão automática, então sed apenas imprime o que é definitivamente dito para p rint. A única vez que é definitivamente solicitado para imprimir é quando ele pode remover com sucesso uma sequência de 0 ou mais caracteres que não sejam = e um caractere que seja = .

Se você quisesse imprimir toda a linha correspondente, você poderia fazer:

sed -n '/part2/q;/=/p'
    
por 22.08.2014 / 14:15