Скрипты Bash - как объединить следующие строки?

8

Вот часть bashсценария, выполняющая cpuidобнаружение в 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`

Итак, для моего ноутбука эта часть скрипта (показанная здесь) дает 60.

Теперь, как это сделать, используя ТОЛЬКО локальные переменные, без cpu.txtучастия промежуточного файла ( )?

никто
источник

Ответы:

10

На одном дыхании:

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

Приведенное выше использует процесс substitution ( <()) и команду substitution ( $()).

  • Две подстановки команд заменены на STDOUT команд внутри

  • cpuidкоманда помещается внутрь процесса подстановки, STDOUT будет возвращен как дескриптор файла, grepвыполнит необходимое сопоставление с ним, мы использовали grepс PCRE ( -P), чтобы получить только ( -o) нужную часть, и -m1остановимся после первого совпадения, чтобы избежать повторения

  • printf используется для получения вывода в желаемом формате

Пример:

$ printf '%s%s\n' "$(grep -Pom1 'extended model.*\(\K\d+' <(cpuid))" "$(grep -Pom1 'extended family.*\(\K\d+' <(cpuid))"
30
heemayl
источник
9

Вы можете избежать использования промежуточного файла, используя канал , и вы можете избежать использования обоих, sedа awkтакже выполнить сопоставление и подстановку, awkнапример,

/usr/bin/cpuid | 
  awk '/extended model/ {mod = substr($4,3)} /extended family/ {fam = substr($4,3)} 
  END {printf "%d%d\n", mod, fam}'
steeldriver
источник
1

Не делая предположений и не меняя природу выборки, вот капля замены, которая сохраняет выходные данные в переменной по запросу:

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

Первая строка устанавливает переменную CPUIDна выход /usr/bin/cpuid
I, затем устанавливает переменную aравной output ( echo) CPUIDпеременной, установленной в строке выше (это затем передается по указанным вами командам).

NGRhodes
источник
1
Спасибо за объяснение. Этот самый близкий к моему уровню понимания. К сожалению, я не эксперт в sed, awk и perl, но некоторое первоначальное понимание у меня есть. :-)
никто не
1
В catпервой строке не должно быть там. Это заставляет CPUID назначать содержимое двоичного исполняемого файла, а не его вывод.
Джо
0

СЭД

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

так как у меня 8 ядер, мой компьютер излучает:

50  
50  
50  
50  
50  
50  
50  
50  

tac меняет порядок строк в cpuid, так что я могу использовать ^ CPU в качестве ограничителя записи CPU, а также расширенная модель и расширенное семейство, расположенные в правильном порядке

Сэм Лиддикотт
источник
0

Это не оптимизирует ваши начальные команды, но точка с запятой позволяет вам соединить 2 команды, чтобы полностью избежать операции конкатенации:

foo="$(firstcommand; secondcommand)"

Или, в зависимости от вашей ситуации:

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

Если вы заботитесь о новых строках, вам нужно ставить двойные кавычки до начала $(и после закрытия)

Питер Бауэрс
источник
0

Вот способ сделать это в awk(весь вывод, как сделано кодом в вашем ответе).

Когда вы заканчиваете тем, что обрабатываете тот же самый ввод снова и снова, это обычно указывает, что другой подход мог бы быть лучше.

awkидеально подходит для обработки ввода текста, как это. awkпрограммы намного длиннее, чем выполняемые sed, но их гораздо легче читать, и вы можете добавить к ним операторы печати, чтобы сделать отладку намного проще.

Я оставил свои отладочные заявления в (закомментированный). Вы можете раскомментировать их, чтобы посмотреть, как работает скрипт.

Вы должны поместить awkпрограмму куда-нибудь, и самое простое место в одном случае использования - это поместить все это в одну строку в кавычках в awkкомандной строке.

Таким образом, вам не нужно хранить его в отдельном файле или во временном файле, поэтому управление файлами не требуется, и скрипт будет работать сам по себе.

Эта программа выглядит долго, но это почти все комментарии, операторы отладки и пробелы.

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

Пока я читаю все комментарии и постараюсь использовать их все. Как я писал NGRhodes: «к сожалению, я не эксперт в sed, awk и perl, но у меня есть некоторое первоначальное понимание.

Большое спасибо всем, кто сделал / представил эти прекрасные примеры. Я искренне надеюсь, что намного больше людей будут читать эти строки и углублять свои навыки написания сценариев!

На самом деле, я сделал коктейль из того, что вы мне все предложили:

/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

Результат: 40651 0004-0651-0000-0000-0000-0000, чего я и ожидаю! :-)

никто
источник
Если вы собираетесь делать все это и использовать awk в любом случае, было бы лучше переписать все это как небольшую awk-программу. Также, смотрите мой комментарий к ответу @NGRhodes о том, почему эта первая строка не работает.
Джо