Script di Bash: come concatenare le seguenti stringhe?


8

Ecco la parte dello bashscript che fa cpuidscoperta in 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`

Quindi, per il mio laptop questa parte della sceneggiatura (mostrata qui) ne fornisce 60.

Ora come fare usando SOLO variabili locali, senza il file intermedio ( cpu.txt) coinvolto?

Risposte:


10

In un colpo solo:

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

Quanto sopra sfrutta la sostituzione di processo ( <()) e la sostituzione di comando ( $()).

  • Le due sostituzioni di comandi vengono sostituite con STDOUT dei comandi all'interno

  • cpuidil comando viene inserito nella sostituzione del processo, lo STDOUT verrà restituito come descrittore di file, grepfarà la corrispondenza necessaria su di esso, abbiamo usato grepcon PCRE ( -P) per ottenere solo ( -o) la porzione desiderata e -m1si fermerà dopo la prima corrispondenza per evitare la ripetizione

  • printf viene utilizzato per ottenere l'output nel formato desiderato

Esempio:

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

9

È possibile evitare il file intermedio utilizzando una pipe e si può evitare di utilizzare entrambi sede awkfacendo corrispondenze e sostituzioni, ad awkes

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

1

Senza fare ipotesi e cambiare la natura del campione, ecco un calo nella sostituzione che memorizza l'output in una variabile come richiesto:

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 prima riga imposta la variabile CPUIDsull'output di /usr/bin/cpuid
I, quindi imposta la variabile acome output ( echo) della CPUIDvariabile impostata nella riga sopra (questa viene quindi reindirizzata ai comandi forniti).


1
Grazie per la spiegazione. Questo è il più vicino al mio livello di comprensione. Sfortunatamente, non sono esperto di sed, awk e perl, ma ho una comprensione iniziale che ho. :-)
nessuno

1
La catprima riga non dovrebbe essere lì. Fa sì che al CPUID vengano assegnati i contenuti dell'eseguibile binario anziché il suo output.
Joe,

0

sed

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

poiché ho 8 core, il mio PC emette:

50  
50  
50  
50  
50  
50  
50  
50  

tac inverte l'ordine delle linee da cpuid in modo che io possa usare ^ CPU come terminatore di un record CPU, un modello anche esteso e una famiglia estesa quindi si verificano nell'ordine giusto


0

Questo non ottimizza i tuoi comandi iniziali, ma il punto e virgola ti consente di mettere insieme 2 comandi per evitare del tutto l'operazione di concatenazione:

foo="$(firstcommand; secondcommand)"

Oppure, specifico per la tua situazione:

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

Se ti interessano le newline vorrai mettere virgolette doppie prima dell'iniziale $(e dopo la chiusura)


0

Ecco un modo per farlo in awk(l'intero output come fatto dal codice nella tua risposta).

Quando si finisce per rielaborare più volte lo stesso input, di solito indica che un altro approccio potrebbe essere migliore.

awkè perfetto per elaborare l'immissione di testo in questo modo. awki programmi sono molto più lunghi delle cose fatte sed, ma sono molto più facili da leggere e puoi aggiungere istruzioni di stampa per rendere il debugging molto più semplice.

Ho lasciato le mie dichiarazioni di debug (commentate). Puoi decommentarli per vedere come funziona lo script.

Devi mettere il awkprogramma da qualche parte e il posto più semplice in un singolo caso d'uso come questo è quello di mettere il tutto in una singola stringa tra virgolette sulla awkriga di comando.

In questo modo non è necessario memorizzarlo in un file separato o in un file temporaneo, quindi non è necessaria la gestione dei file e lo script rimarrà da solo.

Questo programma sembra lungo, ma quasi tutti i commenti, le dichiarazioni di debug e gli spazi bianchi.

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

Finora, sto leggendo tutti i commenti e cercherò di usarli tutti. Come ho scritto a NGRhodes: "sfortunatamente non sono esperto di sed, awk e perl, ma ho una comprensione iniziale che ho.

Mille grazie a tutti coloro che hanno fatto / presentato questi esempi eccellenti. Spero sinceramente che molte più persone leggano queste righe e approfondiscano le loro abilità di sceneggiatore!

In realtà, ho fatto un cocktail di ciò che mi hai suggerito:

/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

Il risultato è: 40651 0004-0651-0000-0000-0000-0000 che è quello che mi aspetto! :-)


Se hai intenzione di fare tutto questo e usare comunque awk, risulterebbe più pulito riscrivere il tutto come un piccolo programma awk. Inoltre, vedi il mio commento alla risposta di @NGRhodes sul perché quella prima riga non funziona.
Joe,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.