Bash scripting - comment concaténer les chaînes suivantes?

8

Voici la partie du bashscript faisant la cpuiddécouverte sous 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`

Donc, pour mon ordinateur portable, cette partie du script (illustré ici) donne 60.

Maintenant, comment faire cela en utilisant UNIQUEMENT des variables locales, sans cpu.txtimpliquer le fichier intermédiaire ( )?

personne
la source

Réponses:

10

En une fois:

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

Ce qui précède utilise la substitution de processus ( <()) et la substitution de commandes ( $()).

  • Les deux substitutions de commandes sont remplacées par le STDOUT des commandes à l'intérieur

  • cpuidla commande est placée à l'intérieur de la substitution de processus, la STDOUT sera retournée comme descripteur de fichier, grepfera la correspondance nécessaire dessus, nous l'avons utilisée grepavec PCRE ( -P) pour obtenir seulement ( -o) la partie souhaitée, et -m1s'arrêtera après la première correspondance pour éviter la répétition

  • printf est utilisé pour obtenir la sortie au format souhaité

Exemple:

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

Vous pouvez éviter le fichier intermédiaire en utilisant un canal , et vous pouvez éviter d'utiliser les deux sedet awken faisant votre correspondance et substitution par awkexemple

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

Sans faire d'hypothèses et sans changer la nature de l'échantillon, voici une baisse de remplacement qui stocke la sortie dans une variable comme demandé:

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 } ')

La première ligne définit la variable CPUIDsur la sortie de /usr/bin/cpuid
I, puis définit la variable acomme la sortie ( echo) de la CPUIDvariable définie dans la ligne ci-dessus (elle est ensuite redirigée vers les commandes fournies).

NGRhodes
la source
1
Merci pour l'explication. Celui-ci est le plus proche de mon niveau de compréhension. Malheureusement, je ne suis pas expert en sed, awk et perl, mais j'ai une première compréhension. :-)
personne
1
Le catdans la première ligne ne devrait pas être là. Elle fait que CPUID se voit attribuer le contenu de l'exécutable binaire plutôt que sa sortie.
Joe
0

sed

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

comme j'ai 8 cœurs, mon pc émet:

50  
50  
50  
50  
50  
50  
50  
50  

tac inverse l'ordre des lignes de cpuid afin que je puisse utiliser ^ CPU comme terminateur d'un enregistrement CPU, un modèle également étendu et une famille étendue apparaissent ensuite dans le bon ordre

Sam Liddicott
la source
0

Cela n'optimise pas vos commandes initiales, mais le point-virgule vous permet de regrouper 2 commandes pour éviter complètement l'opération de concaténation:

foo="$(firstcommand; secondcommand)"

Ou, spécifique à votre situation:

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

Si vous vous souciez des nouvelles lignes, vous voudrez mettre des guillemets doubles avant l'initiale $(et après la fermeture)

Peter Bowers
la source
0

Voici un moyen de le faire awk(la sortie entière comme le fait le code dans votre réponse).

Lorsque vous finissez par retraiter la même entrée encore et encore, cela indique généralement qu'une autre approche pourrait être meilleure.

awkest parfait pour le traitement de texte comme celui-ci. awkles programmes sont beaucoup plus longtemps que les choses avec sed, mais ils sont beaucoup plus faciles à lire et vous pouvez les ajouter des instructions d'impression pour faire le débogage beaucoup plus facile.

J'ai laissé mes déclarations de débogage dans (commenté). Vous pouvez les décommenter pour voir comment fonctionne le script.

Vous devez mettre le awkprogramme quelque part et l'endroit le plus simple dans un cas d'utilisation unique comme celui-ci est de mettre le tout dans une seule chaîne entre guillemets sur la awkligne de commande.

De cette façon, vous n'avez pas besoin de le stocker dans un fichier séparé ou dans un fichier temporaire, il n'y a donc pas de gestion de fichiers impliquée et le script sera autonome.

Ce programme semble long, mais c'est presque tous les commentaires, les instructions de débogage et l'espace blanc.

#!/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
}
'
Joe
la source
0

Jusqu'à présent, je lis tous les commentaires et je vais essayer de les utiliser tous. Comme je l 'ai écrit à NGRhodes: "malheureusement, je ne suis pas expert en sed, awk et perl, mais j'ai une première compréhension.

Un grand merci à tous ceux qui ont fait / présenté ces excellents exemples. J'espère sincèrement que beaucoup plus de gens liront ces lignes et approfondiront leurs compétences de script!

En fait, j'ai fait un cocktail de ce que vous m'avez tous suggéré:

/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

Le résultat est: 40651 0004-0651-0000-0000-0000-0000 ce que j'attends! :-)

personne
la source
Si vous voulez faire tout cela et utiliser awk de toute façon, il serait plus propre de réécrire le tout en un petit programme awk. Voir aussi mon commentaire à la réponse @NGRhodes pour savoir pourquoi cette première ligne ne fonctionne pas.
Joe