Bashスクリプト-次の文字列を連結する方法は?


8

Linux(Ubuntu / Fedora)で検出を実行するbashスクリプトの一部を次に示しますcpuid

/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))"

上記は、プロセス置換(<())とコマンド置換($())を利用しています。

  • 2つのコマンド置換は、内部のコマンドの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

9

パイプを使用することで中間ファイルを回避することができ、両方sedを使用することを回避しawkawkたとえば、

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

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の出力(echo)にCPUID設定します(これは指定されたコマンドにパイプされます)。


1
ご説明ありがとうございます。これは私の理解レベルに最も近いものです。残念ながら、私はsed、awk、およびperlの専門家ではありませんが、いくつかの初期の理解があります。:-)
だれも

1
cat最初の行であってはなりません。これにより、CPUIDには、出力ではなくバイナリ実行可能ファイルの内容が割り当てられます。
Joe

0

sed

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

私は8コアを持っているので、私のPCは次のように排出します:

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の回答に対する私のコメントを参照してください。
Joe
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.