我是 Unix 脚本的新手,所以请耐心等待。
我得到了一个文件,其中包含有关每行进程的信息。我需要从每一行中提取有关这些过程的某些信息。
文件示例 -
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>
Run Code Online (Sandbox Code Playgroud)
所需的输出是 -
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
Run Code Online (Sandbox Code Playgroud)
每行的数字 1、2 和 3 仅表示输出文件的行号。
我已经尝试使用该sed
s/
命令,但它是特定于顺序的,而输入文件中的参数不遵循顺序 - 因此,输入文件中的某些行被跳过。
这是我的命令-
sed -nr 'appId/s/(\w+).*port=([^ ]+) .*authenticate=[^ ]+) .*appId=[^ ]+) .*/\2\t\3\t\4/p' | sed =
Run Code Online (Sandbox Code Playgroud)
任何人都可以指导我如何不考虑顺序提取这些参数吗?
谢谢!
编辑 1:我设法以这种方式使用 grep 的后视零宽度断言功能 -
grep -Po '(?<=pattern1=)[^ ,]+|(?<=pattern2=)[^ ,]+|(?<=pattern3=)[^ ,]+|(?<=pattern4=)[^ ,]+' filename
Run Code Online (Sandbox Code Playgroud)
但这似乎给出了新行中每一行的输出,即
1234
true
dummyAppId1
Run Code Online (Sandbox Code Playgroud)
试图弄清楚如何使用 grep 将它放在一行上(即不是通过将 X 行合并为 1)
编辑 2:混淆输入中参数的顺序
编辑 3:对不起,我应该早点提到这一点 -perl
似乎在我工作的机器上受到限制。虽然 Stephane 和 Sundeep 提供的答案在我本地测试时完美地工作,但它在我需要它最终运行的机器上不起作用。看起来 awk、grep 和 sed 是主要支持的选项:(
With 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
Run Code Online (Sandbox Code Playgroud)
和 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
Run Code Online (Sandbox Code Playgroud)
(?=.*(port=[^ ]+))
第一个捕获组 port
(?=.*(authenticate=[^ ]+))
第二个捕获组authenticate
,以此类推print $.
对于行号\bport
,\bappID
等等,如果单词边界是不够的。否则,使用(?<!\S)(port=[^ ]+)
基于空格的限制。如果您需要打印只包含线appID
或任何其他这种条件下,改变-lpe
以-lne
和变化print $.
,以print "$.\n$_" if /appID/
使用perl
,您可以使用以下方法:
perl -lne 'my %h;
$h{$1} = $& while /(\S+?)=(\S+)/g;
print "@h{qw(port authenticate appID)}"'
Run Code Online (Sandbox Code Playgroud)
在其中构建一个哈希表,其键是属性名称,值是name=value
s,然后打印您想要的那些。
如果您只想要输出值,请替换$&
为$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"]
}'
Run Code Online (Sandbox Code Playgroud)
使用pcregrep
,您可以执行以下操作:
pcregrep -o1 -o2 -o3 --om-separator=' ' '(?x)
^(?=.*?\s(port=\S+))
(?=.*?\s(authenticate=\S+))
(?=.*?\s(appID=\S+))'
Run Code Online (Sandbox Code Playgroud)
(那个要求所有三个属性都存在)。
与sed
:
sed 'G
s/[[:space:]]\(port=[^[:space:]]*\).*\n.*/&\1/
s/[[:space:]]\(authenticate=[^[:space:]]*\).*\n.*/& \1/
s/[[:space:]]\(appID=[^[:space:]]*\).*\n.*/& \1/
s/.*\n//'
Run Code Online (Sandbox Code Playgroud)
最后两个假设属性不是该行的第一个单词(鉴于您的样本,这似乎是一个合理的假设)。
归档时间: |
|
查看次数: |
452 次 |
最近记录: |