web-dev-qa-db-fra.com

Script Bash - Comment concaténer les chaînes suivantes?

Voici la partie du script bash effectuant la découverte de cpuid 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`

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

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

8
nobody

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 exploite la substitution de processus (<()) et la substitution de commande ($()).

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

  • La commande cpuid est insérée dans la substitution de processus, le STDOUT sera renvoyé sous forme de descripteur de fichier, grep fera la correspondance nécessaire, nous avons utilisé grep avec PCRE (-P) pour obtenir seulement (-o) la portion souhaitée, et -m1 s'arrêtera après le premier match pour éviter les répétitions

  • 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
10
heemayl

Vous pouvez éviter le fichier intermédiaire en utilisant pipe, et vous pouvez éviter d'utiliser à la fois sed et awk en faisant votre correspondance et votre substitution dans awk par exemple.

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

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 CPUID sur la sortie de /usr/bin/cpuid
J'ai ensuite défini la variable a comme sortie (echo) de la variable CPUID définie dans la ligne ci-dessus (elle est ensuite acheminée vers les commandes fournies).

1
NGRhodes

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 un expert pour sed, awk et Perl, mais une compréhension initiale que j’ai.

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

En fait, j'ai préparé 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-00 c'est ce que j'attends! :-)

0
nobody

Cela n'optimise pas vos commandes initiales, mais le point-virgule vous permet de mettre 2 commandes ensemble pour éviter entièrement 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 avant le $( initial et après le ) final

0
Peter Bowers

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 de CPU, ainsi qu'un modèle et une famille étendus apparaissent dans le bon ordre.

0
Sam Liddicott

Voici un moyen de le faire dans awk (le résultat complet tel qu’indiqué par le code de votre réponse).

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

awk est parfait pour le traitement de texte tel que celui-ci. Les programmes awk sont beaucoup plus longs que les opérations effectuées avec sed, mais ils sont beaucoup plus faciles à lire et vous pouvez leur ajouter des instructions d'impression pour faciliter le débogage beaucoup.

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

Vous devez placer le programme awk quelque part et, dans un cas d'utilisation unique comme celui-ci, le plus simple consiste à mettre le tout dans une seule chaîne entre guillemets sur la ligne de commande awk.

De cette façon, vous n'avez pas besoin de le stocker dans un fichier séparé ou dans un fichier temporaire. Par conséquent, aucune gestion de fichier n'est nécessaire et le script est autonome.

Ce programme a l'air long, mais il contient presque tous les commentaires, les instructions de débogage et les espaces.

#!/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
Joe