Bash scripting: ¿cómo concatenar las siguientes cadenas?

8

Aquí está la parte del bashscript que hace cpuiddescubrimiento en 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`

Entonces, para mi computadora portátil, esta parte del script (que se muestra aquí) da 60.

Ahora, ¿cómo hacer esto usando SOLO variables locales, sin cpu.txtinvolucrar el archivo intermedio ( )?

nadie
fuente

Respuestas:

10

En una ida:

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

Lo anterior aprovecha la sustitución de procesos ( <()) y la sustitución de comandos ( $()).

  • Las dos sustituciones de comandos se reemplazan con el STDOUT de los comandos dentro

  • cpuidel comando se coloca dentro de la sustitución del proceso, el STDOUT se devolverá como un descriptor de archivo, grephará la coincidencia necesaria en él, lo hemos utilizado grepcon PCRE ( -P) para obtener solo ( -o) la porción deseada y -m1se detendrá después de la primera coincidencia para evitar la repetición

  • printf se usa para obtener la salida en el formato deseado

Ejemplo:

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

Puede evitar el archivo intermedio utilizando una tubería , y puede evitar el uso de ambos sedy awkhaciendo su coincidencia y sustitución en, awkpor ejemplo,

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

Sin hacer suposiciones y cambiar la naturaleza de la muestra, aquí hay una caída en el reemplazo que almacena la salida en una variable según lo 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 } ')

La primera línea establece la variable CPUIDen la salida de /usr/bin/cpuid
I, luego establece la variable apara que sea la salida ( echo) de la CPUIDvariable establecida en la línea anterior (esto se canaliza a los comandos proporcionados).

NGRhodes
fuente
1
Gracias por la explicación. Este es el más cercano a mi nivel de comprensión. Desafortunadamente, no soy experto en sed, awk y perl, pero sí tengo una comprensión inicial. :-)
nadie
1
El caten la primera línea no debería estar allí. Hace que a CPUID se le asignen los contenidos del ejecutable binario en lugar de su salida.
Joe
0

sed

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

Como tengo 8 núcleos, mi PC emite:

50  
50  
50  
50  
50  
50  
50  
50  

tac invierte el orden de las líneas de cpuid para que pueda usar ^ CPU como terminador de un registro de CPU, un modelo también extendido y una familia extendida luego ocurren en el orden correcto

Sam Liddicott
fuente
0

Esto no optimiza sus comandos iniciales, pero el punto y coma le permite poner 2 comandos juntos para evitar la operación de concatenación por completo:

foo="$(firstcommand; secondcommand)"

O, específico a su situación:

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

Si le interesan las nuevas líneas, querrá poner comillas dobles antes de la inicial $(y después del cierre.)

Peter Bowers
fuente
0

Aquí hay una manera de hacerlo awk(toda la salida como lo hace el código en su respuesta).

Cuando termina reprocesando la misma entrada una y otra vez, generalmente indica que otro enfoque podría ser mejor.

awkes perfecto para procesar entradas de texto como esta. awklos programas son mucho más tiempo que las cosas se hagan con sed, pero son mucho más fáciles de leer y se puede agregar instrucciones de impresión para ellos para hacer la depuración mucho más fácil.

Dejé mis declaraciones de depuración en (comentado). Puede descomentarlos para ver cómo funciona el guión.

Debe colocar el awkprograma en algún lugar y el lugar más fácil en un caso de uso único como este es colocar todo en una sola cadena entre comillas en la awklínea de comando.

De esta manera, no tiene que almacenarlo en un archivo separado o en un archivo temporal, por lo que no hay gestión de archivos involucrada y el script se mantendrá por sí solo.

Este programa parece largo, pero es casi todos los comentarios, declaraciones de depuración y espacios en blanco.

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

Hasta ahora, estoy leyendo todos los comentarios e intentaré usarlos todos. Como le escribí a NGRhodes: "desafortunadamente, no soy experto en sed, awk y perl, pero sí tengo cierta comprensión inicial.

Muchas gracias a todos los que hicieron / presentaron estos excelentes ejemplos. ¡Espero sinceramente que mucha más gente lea estas líneas y profundice sus habilidades de secuencias de comandos!

En realidad, hice un cóctel de lo que todos ustedes me sugirieron:

/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

El resultado es: 40651 0004-0651-0000-0000-0000-0000 que es lo que espero! :-)

nadie
fuente
Si va a hacer todo eso y usar awk de todos modos, sería más adecuado reescribir todo como un pequeño programa awk. Además, vea mi comentario a la respuesta de @NGRhodes sobre por qué esa primera línea no funciona.
Joe