Script Bash - como concatenar as seguintes strings?


8

Aqui está a parte do bashscript que faz a cpuiddescoberta no Linux (Ubuntu / Fedora):

/usr/bin/cpuid > id.txt    
CPUID=id.txt    
echo `grep "extended model" $CPUID` | sed 's/0x//' | awk ' { print $4 } ' > cpu.txt    
a=`cat cpu.txt`    
echo `grep "extended family" $CPUID`| sed 's/0x//' | awk ' { print $4 } ' > cpu.txt    
a+=`cat cpu.txt`

Portanto, para o meu laptop, essa parte do script (mostrada aqui) fornece 60.

Agora, como fazer isso usando APENAS variáveis ​​locais, sem ter o arquivo intermediário ( cpu.txt) envolvido?

Respostas:


10

Numa única tentativa:

printf '%s%s\n' "$(grep -Pom1 'extended model.*\(\K\d+' <(cpuid))" \
                "$(grep -Pom1 'extended family.*\(\K\d+' <(cpuid))"

O exemplo acima aproveita a substituição do processo ( <()) e a substituição do comando ( $()).

  • As duas substituições de comando são substituídas pelo STDOUT dos comandos dentro

  • cpuidO comando é colocado dentro da substituição do processo, o STDOUT será retornado como um descritor de arquivo, grepfará a correspondência necessária, usamos grepcom PCRE ( -P) para obter apenas ( -o) a parte desejada e -m1paramos após a primeira correspondência para evitar repetições

  • printf é usado para obter a saída no formato desejado

Exemplo:

$ printf '%s%s\n' "$(grep -Pom1 'extended model.*\(\K\d+' <(cpuid))" "$(grep -Pom1 'extended family.*\(\K\d+' <(cpuid))"
30

9

Você pode evitar o arquivo intermediário usando um pipe e pode evitar os dois sede awkfazer sua correspondência e substituição, por awkexemplo,

/usr/bin/cpuid | 
  awk '/extended model/ {mod = substr($4,3)} /extended family/ {fam = substr($4,3)} 
  END {printf "%d%d\n", mod, fam}'

1

Sem fazer suposições e alterar a natureza da amostra, aqui está uma queda na substituição que armazena a saída em uma variável conforme solicitado:

CPUID=$(/usr/bin/cpuid)
a=$(echo "$CPUID" | grep 'extended model' | sed 's/0x//' | awk ' { print $4 } ')
a+=$(echo "$CPUID" | grep 'extended family' | sed 's/0x//' | awk ' { print $4 } ')

A primeira linha define a variável CPUIDcomo a saída de /usr/bin/cpuid
I e, em seguida, define a variável acomo a saída ( echo) da CPUIDvariável definida na linha acima (isso é canalizado para os comandos fornecidos).


1
Obrigado pela explicação. Este é o mais próximo do meu nível de entendimento. Infelizmente, não sou especialista em sed, awk e perl, mas tenho um entendimento inicial. :-)
ninguém

1
A catprimeira linha não deveria estar lá. Faz com que CPUID receba o conteúdo do executável binário em vez de sua saída.
Joe

0

sed

cpuid | tac | sed '/^CPU/{s/.*//;x;s/\n//g;p;d};/extended \(model\|family\)/!d;s/.*(\(.*\)).*/\1/;H;d'

como eu tenho 8 núcleos, meu pc emite:

50  
50  
50  
50  
50  
50  
50  
50  

tac inverte a ordem das linhas do cpuid para que eu possa usar ^ CPU como terminador de um registro de CPU, um modelo também extendido e uma família extendida ocorrem na ordem correta


0

Isso não otimiza seus comandos iniciais, mas o ponto e vírgula permite que você coloque dois comandos juntos para evitar a operação de concatenação inteiramente:

foo="$(firstcommand; secondcommand)"

Ou, específico para sua situação:

a=$(grep "extended model" $CPUID | sed 's/0x//' | awk ' { print $4 };
grep "extended family" $CPUID | sed 's/0x//' | awk ' { print $4 };)

Se você se preocupa com as novas linhas, deverá colocar aspas duplas antes da inicial $(e após o fechamento)


0

Aqui está uma maneira de fazê-lo awk(toda a saída, conforme feito pelo código em sua resposta).

Quando você acaba reprocessando a mesma entrada repetidamente, geralmente indica que outra abordagem pode ser melhor.

awké perfeito para processar entrada de texto como esta. awkprogramas são muito mais do que as coisas sejam feitas com sed, mas eles são muito mais fáceis de ler e você pode adicionar instruções de impressão para eles para fazer a depuração muito mais fácil.

Deixei minhas instruções de depuração em (comentadas). Você pode descomentá-los para ver como o script funciona.

Você precisa colocar o awkprograma em algum lugar e o lugar mais fácil em um único caso de uso como esse é colocar tudo em uma única cadeia de caracteres entre aspas na awklinha de comando.

Dessa forma, você não precisa armazená-lo em um arquivo separado ou em um arquivo temporário; portanto, não há gerenciamento de arquivos envolvido e o script permanecerá por si próprio.

Este programa parece longo, mas são quase todos os comentários, instruções de depuração e espaço em branco.

#!/bin/bash

## Whole awk program is one single quoted string
## on the awk command line
## so we don't need to put it in a separate file 
## and so bash doesn't expand any of it
## Debugging statements were left in, but commented out

/usr/bin/cpuid | awk '
BEGIN {  ## initialize variables - probably unnecessary
  em = ""
  ef = ""
  fa = ""
  mo = ""
  si = ""
  ps = ""
}

## get each value only once

## extended model is in field 4 starting at the third character
## of a line which contains "extended model"
/extended model/ && em == "" {
  em = substr($4, 3)
  ##print "EM " em
}

## extended family is in field 4 starting at the third character
## of a line which contains "extended family"
/extended family/ && ef == "" {
  ef = substr($4, 3)
  ##print "EF " ef
}

## family is in the last field, starting at the second character
## and is two characters shorter than the field "()"
## of a line which starts with "family"
## (so it does not match "extended family")
$1 == "family" && fa == "" {
  ##print NF " [" $NF "]"
  ##print "[" substr($NF, 2) "]"
  l = length($NF) - 2
  fa = substr($NF, 2, l)
  ##print "FA " fa
}

## model is in the third field, starting at the third character
## of a line which starts with "model"
## (so it does not match "extended model")
$1 == "model" && mo == "" {
  mo = substr($3, 3)
  ##print "MO " mo
}


## stepping id is in field 4 starting at the third character
## of a line which contains "stepping id"
/stepping id/ && si == "" {
  si = substr($4, 3)
  ##print "SI " si
}

## processor serial number is in field 4 starting at the third character
## of a line which contains "processor serial number:"
/processor serial number:/ && ps == "" {
  ps = $4
  ##print "PS " ps
}

## Quit when we have all the values we need
em != "" && ef != "" && fa != "" && mo != "" && si != "" && ps != "" {
  exit
}

END {
  print em ef fa mo si " " ps
}
'

0

Até agora, estou lendo todos os comentários e tentarei usá-los todos. Como escrevi para o NGRhodes: "infelizmente, não sou especialista em sed, awk e perl, mas tenho algum entendimento inicial.

Muito obrigado a todos que apresentaram / apresentaram esses excelentes exemplos. Espero sinceramente que mais pessoas leiam essas linhas e aprofundem suas habilidades de script!

Na verdade, fiz um coquetel do que todos vocês me sugeriram:

/usr/bin/cpuid > id.txt  ***[CPUID=$(cat /usr/bin/cpuid) does not work for me]***  
CPUID=id.txt  
a=$(echo `cat $CPUID | grep -m1 'extended model' | sed 's/0x//' | awk ' { print $4 } '`)  
a+=$(echo `cat $CPUID | grep -m1 'extended family' | sed 's/0x//' | awk ' { print $4 } '`)  
a+=$(echo `cat $CPUID | grep -m1 'AMD' | sed 's/(//' | sed 's/)//' | awk ' { print $13 } '`)  
a+=$(echo `cat $CPUID | grep -m1 'model' | sed 's/0x//' | awk ' { print $3 } '`)  
a+=$(echo `cat $CPUID | grep -m1 'stepping id' | sed 's/0x//' | awk ' { print $4 } '`)  
a+=' '  
a+=$(echo `cat $CPUID | grep -m1 'processor serial number:' | awk ' { print $4 } '`)  
echo $a

O resultado é: 40651 0004-0651-0000-0000-0000-0000 que é o que eu espero! :-)


Se você fizer tudo isso e usar o awk de qualquer maneira, seria mais fácil reescrever tudo como um pequeno programa do awk. Além disso, veja meu comentário na resposta @NGRhodes sobre por que essa primeira linha não funciona.
Joe
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.