Skrypty Bash - jak połączyć następujące ciągi?

8

Oto część bashskryptu przeprowadzająca cpuidwykrywanie w systemie 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`

Tak więc dla mojego laptopa ta część skryptu (pokazana tutaj) daje 60.

Teraz, jak to zrobić, używając TYLKO zmiennych lokalnych, bez cpu.txtudziału pliku pośredniego ( )?

nikt
źródło

Odpowiedzi:

10

Za jednym razem:

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

Powyżej wykorzystuje proces podstawienia ( <()) i podstawienia polecenia ( $()).

  • Dwie substytucje komend są zastępowane STDOUT komend w środku

  • cpuidpolecenie zostało wstawione do podstawienia procesu, STDOUT zostanie zwrócony jako deskryptor pliku, grepdokona na nim niezbędnego dopasowania, użyliśmy grepz PCRE ( -P), aby uzyskać tylko ( -o) żądaną część, i -m1zatrzyma się po pierwszym dopasowaniu, aby uniknąć powtórzenia

  • printf służy do uzyskania wyniku w żądanym formacie

Przykład:

$ printf '%s%s\n' "$(grep -Pom1 'extended model.*\(\K\d+' <(cpuid))" "$(grep -Pom1 'extended family.*\(\K\d+' <(cpuid))"
30
heemayl
źródło
9

Możesz uniknąć pliku pośredniego, używając potoku , a możesz uniknąć korzystania z obu sedi awkdopasowując i zastępując awknp

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

Bez przyjmowania założeń i zmiany charakteru próbki, oto spadek zastępowania, który przechowuje dane wyjściowe w zmiennej zgodnie z żądaniem:

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

Pierwszy wiersz ustawia zmienną CPUIDna wyjście /usr/bin/cpuid
I, a następnie ustawiam zmienną ana wynik ( echo) CPUIDzmiennej ustawionej w powyższym wierszu (jest to następnie przesyłane potokowo do podanych poleceń).

NGRhodes
źródło
1
Dziękuję za wyjaśnienie. Ten jest najbliższy mojemu poziomowi zrozumienia. Niestety nie jestem ekspertem od sed, awk i perl, ale mam pewne wstępne zrozumienie. :-)
nikt
1
catW pierwszej linii nie powinno tam być. Powoduje, że CPUID przypisuje zawartość binarnego pliku wykonywalnego, a nie jego wynik.
Joe
0

sed

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

ponieważ mam 8 rdzeni, mój komputer emituje:

50  
50  
50  
50  
50  
50  
50  
50  

tac odwraca kolejność linii od cpuid, dzięki czemu mogę użyć ^ CPU jako terminatora rekordu procesora, a także rozszerzony model i rozszerzona rodzina następnie występują we właściwej kolejności

Sam Liddicott
źródło
0

Nie optymalizuje to początkowych poleceń, ale średnik pozwala na połączenie 2 poleceń, aby całkowicie uniknąć operacji konkatenacji:

foo="$(firstcommand; secondcommand)"

Lub specyficzne dla twojej sytuacji:

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

Jeśli zależy Ci na nowej linii, będziesz chciał wstawić podwójne cudzysłowy przed początkowym $(i po zamknięciu)

Peter Bowers
źródło
0

Oto sposób, aby to zrobić awk(cały wynik, jak to zrobiono w kodzie w odpowiedzi).

Ponowne przetwarzanie tych samych danych wejściowych raz za razem zwykle oznacza, że ​​inne podejście może być lepsze.

awkjest idealny do przetwarzania wprowadzania tekstu w ten sposób. awkprogramy są znacznie dłuższe niż rzeczy zrobione sed, ale są znacznie łatwiejsze do odczytania i można do nich dodawać instrukcje print, aby znacznie ułatwić debugowanie .

Zostawiłem swoje instrukcje debugowania w (skomentowano). Możesz odkomentować je, aby zobaczyć, jak działa skrypt.

Musisz awkgdzieś umieścić program, a najłatwiejszym miejscem w jednym przypadku użycia, takim jak ten, jest umieszczenie całości w jednym cudzysłowie w awkwierszu poleceń.

W ten sposób nie musisz przechowywać go w osobnym pliku ani w pliku tymczasowym, więc zarządzanie plikami nie jest związane, a skrypt będzie działał sam.

Ten program wygląda na długi, ale prawie wszystkie komentarze, instrukcje debugowania i białe znaki.

#!/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
źródło
0

Do tej pory czytam wszystkie komentarze i spróbuję je wszystkie wykorzystać. Jak napisałem do NGRhodes: „nie jestem ekspertem od sed, awk i perl, ale mam pewne wstępne zrozumienie.

Ogromne podziękowania dla wszystkich, którzy zrobili / zaprezentowali te doskonałe przykłady. Mam szczerą nadzieję, że wiele osób przeczyta te wiersze i pogłębi swoje umiejętności skryptowe!

Właściwie zrobiłem koktajl tego, co wszyscy mi zaproponowaliście:

/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

Rezultat to: 40651 0004-0651-0000-0000-0000-0000, czego oczekuję! :-)

nikt
źródło
Jeśli masz zamiar to wszystko zrobić i mimo wszystko użyć awk, byłoby lepiej, gdyby przepisał to wszystko jako mały program awk. Zobacz także mój komentarz do odpowiedzi na @NGRhodes, dlaczego ta pierwsza linia nie działa.
Joe