私はUnixスクリプトが初めてなので、ご了承ください。
1行あたりのプロセスに関する情報を含むファイルを取得します。各行からこれらのプロセスに関する特定の情報を抽出する必要があります。
ファイルの例 -
process1 port=1234 appID=dummyAppId1 authenticate=true <some more params>
process3 port=1244 authenticate=false appID=dummyAppId2 <some more params>
process2 appID=dummyAppId3 port=1235 authenticate=true <some more params>
希望の出力は -
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
各行の数字 1、2、3 は出力ファイルの行番号のみを表します。
コマンドを試してみましたが、sed
s/
順序によって異なり、入力ファイルのパラメータが順序に従っていません。したがって、入力ファイルの一部の行をスキップしました。
これが私の命令です -
sed -nr 'appId/s/(\w+).*port=([^ ]+) .*authenticate=[^ ]+) .*appId=[^ ]+) .*/\2\t\3\t\4/p' | sed =
順序に関係なく、これらのパラメータを抽出する方法を案内できる人はいますか?
ありがとうございます!
編集1:私はgrepの幅が0の後ろ姿アサーション機能をこのように使用できました。
grep -Po '(?<=pattern1=)[^ ,]+|(?<=pattern2=)[^ ,]+|(?<=pattern3=)[^ ,]+|(?<=pattern4=)[^ ,]+' filename
しかし、これは新しい行の各行の出力を提供するようです。
1234
true
dummyAppId1
grepを使用して1行に配置する方法を見つけようとしています(つまり、X行を1にマージしません)。
編集2:入力のパラメータ順序を混同する
編集3:申し訳ありません。前述したはずですが、perl
私が作業しているコンピュータでは限られているようです。 StephaneとSundeepが提供した答えは、ローカルでテストしたときに完全に機能しましたが、最終的に実行するために必要なコンピュータでは機能しませんでした。 awk、grep、およびsedが主なサポートオプションであるようです。
答え1
使用awk
(テスト済みGNU awk
、他の実装でも機能するかどうかわからない)
$ cat kv.awk
/appID/ {
for (i = 1; i <= NF; i++) {
$i ~ /^port=/ && (a = $i)
$i ~ /^authenticate=/ && (b = $i)
$i ~ /^appID=/ && (c = $i)
}
print NR "\n" a, b, c
}
$ awk -v OFS='\t' -f kv.awk ip.txt
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
そしてperl
$ # note that the order is changed for second line here
$ cat ip.txt
process1 port=1234 authenticate=true appID=dummyAppId1 <some more params>
process3 port=1244 appID=dummyAppId2 authenticate=false <some more params>
process2 port=1235 authenticate=true appID=dummyAppId3 <some more params>
$ perl -lpe 's/(?=.*(port=[^ ]+))(?=.*(authenticate=[^ ]+))(?=.*(appID=[^ ]+)).*/$1\t$2\t$3/; print $.' ip.txt
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
(?=.*(port=[^ ]+))
最初のキャプチャグループport
(?=.*(authenticate=[^ ]+))
セカンドキャプチャグループauthenticate
などprint $.
行番号について- 部分一致を回避するには、単語の境界が十分な場合はetcを使用してください
\bport
。\bappID
それ以外の場合は、(?<!\S)(port=[^ ]+)
空間ベースの制限が使用されます。
含まれている行のみを印刷する必要があるappID
場合、またはそのような条件が異なる場合は、次に-lpe
変更し-lne
て次にprint $.
変更してください。print "$.\n$_" if /appID/
答え2
の場合、perl
次のように使用できます。
perl -lne 'my %h;
$h{$1} = $& while /(\S+?)=(\S+)/g;
print "@h{qw(port authenticate appID)}"'
キーが属性名で値がsのハッシュテーブルを作成し、必要なものをname=value
印刷できます。
値だけを出力したい場合$&
に に変更してください。$2
awk
同じ
awk '
{
split("", h)
for (i = 1; i <= NF; i++)
if (n = index($i, "=")) h[substr($i, 1, n - 1)] = $i
print h["port"], h["authenticate"], h["appID"]
}'
を使用すると、pcregrep
次のことができます。
pcregrep -o1 -o2 -o3 --om-separator=' ' '(?x)
^(?=.*?\s(port=\S+))
(?=.*?\s(authenticate=\S+))
(?=.*?\s(appID=\S+))'
(これを行うには、3つの属性すべてが必要です。)
そしてsed
:
sed 'G
s/[[:space:]]\(port=[^[:space:]]*\).*\n.*/&\1/
s/[[:space:]]\(authenticate=[^[:space:]]*\).*\n.*/& \1/
s/[[:space:]]\(appID=[^[:space:]]*\).*\n.*/& \1/
s/.*\n//'
最後の2つは、属性が行の最初の単語ではないと仮定します(これはサンプルで合理的な仮定のように見えます)。
答え3
編集3によると、以下のように各パラメータの式をsed
生成すると、まだこれを行うことができると思います。s///
sed -nE 's/^(.*)(appID=[^[:blank:]]+\s)(.*)$/\2\t\1\3/
s/^(.*)(authenticate=[^[:blank:]]+\s)(.*)$/\2\t\1\3/
s/^(.*)(port=[^[:blank:]]+\s)(.*)$/\2\t\1\3/
T;=
s/^(([^[:blank:]]+\s+){,3}).*/\1/
p'
s
目的の出力順序に基づいて式の逆順を確認してください。番号付けはスクリプトにも含まれています。前述のように行番号を印刷し、必要な引数の1つが実際に行に存在する場合にのみ行を印刷します。また、あなたsed
は\d
BSDがsed
。 POSIX規格に対応することが可能かもしれませんが、さらに拡張することができます。
ただし、これはすでにかなり長く、出力パラメータが追加されるにつれてより複雑になるため、次のスクリプトがより一般的になる可能性awk
があります。
awk '
BEGIN {ac=ARGC; ARGC=0; OFS="\t"}
{
str=$0; NF=0
for (i=1; i<ac; i++)
if (match(str, ARGV[i]"=[^[:blank:]]*"))
$(NF+1)=substr(str, RSTART, RLENGTH)
}
NF {print ++nr; print}
' -- port authenticate appID
出力する正確なパラメータと表示順序を指定できます。スクリプトは、必須パラメータの1つ以上が実際に行に存在する場合にのみ行を印刷しますawk
。--
答え4
同様の問題を抱えている他のユーザーに役立つ場合は、Rubyを使用して(詳細な)提案をしてください。
# passing the log file as parameter
lines = File.open(ARGV[0]).read.split("\n")
lines.each_with_index do |line, i|
words = line.split(' ')
output = []
puts i + 1
output << words.select { |w| w =~ /port=\d+/ }
output << words.select { |w| w =~ /authenticate=\w+/ }
output << words.select { |w| w =~ /appID=\w+/ }
puts output.join(' ')
end