我有一个这种格式的文件:
[#] OWNER_NAME NAME SIZE
[6] Robottinosino Software 200
[42] Robottinosino Ideas worth zero 188
[12] Robottinosino Ideas worth zero or more 111
[13] I am Batman Hardware 180
[25] Robottinosino Profile Pictures 170
我希望能够使用命令行工具执行以下操作:
my_command "Ideas worth zero"
并得到这个结果:
42
并且不要冒险得到这个结果:
12
我想过使用 grep 来识别行,使用 awk 来获取第一个字段,但我不确定如何可靠且有效地匹配整个“NAME”字段,而不是在哪一列计算文本“OWNER_NAME”和“SIZE”出现在标题中,并通过一些空白修剪来获取中间的所有内容。
请注意,“OWNER_NAME”可能不止一个单词:例如“OWNER_NAME”=“我是蝙蝠侠”。
有什么想法并伴随实施吗?
我在这里必须使用的只是 cat、head、tail、awk、sed、grep、cut 等老家族。
答案1
好的,如果列的长度未知,我会切换到比 bash 更强大的语言:
#!/usr/bin/perl
use warnings;
use strict;
my $string = shift;
open my $FH, '<', '1.txt' or die $!;
my $first_line = <$FH>;
my ($before, $name) = $first_line =~ /(.* )(NAME *)/;
my $column = length $before;
$string .= ' ' x (length($name) - length $string); # adjust the length of $string
while (<$FH>) {
if ($column == index $_, $string, $column) {
/^\[([0-9]+)\]/ and print "$1\n";
}
}
答案2
如果字段宽度是恒定的 - 即您显示的文件格式与您拥有的字段宽度处于最大值 - 您可以使用 GNU awk ( gawk(1)
) 并将FIELDWIDTHS
变量设置为使用固定宽度解析:
gawk -v searchstr="Ideas worth zero" -- '
BEGIN { FIELDWIDTHS="6 15 27 5" } # assuming the final field width is 5
# Pre-process data
{
gsub(/[^[:digit:]]/, "", $1) # strip out non-numbers
for (i = 2; i <= NF; i++)
gsub(/[[:space:]]*$/, "", $i) # strip trailing whitespace
}
# match here
$3 == searchstr { print $1 }
' file.txt
您可以将其包装在 shell 脚本或函数中并进行参数化searchstr
( -v searchstr="$1"
)。
但是,如果字段的宽度可变 - 即如果数据发生变化,字段的宽度可能会发生变化 - 您需要更聪明一点,并通过检查第一行来动态确定字段宽度。鉴于一个字段被称为OWNER_NAME
,使用下划线,我假设字段名称中不存在空格,因此我可以假设空格分隔字段名称。
定义后,您可以BEGIN...
用以下代码替换该行:
NR == 1 {
for (i = 2; i <= NF; i++)
FIELDWIDTHS=FIELDWIDTHS index($0" ", " "$i" ")-index($0" ", " "$(i-1)" ") " "
FIELDWIDTHS=FIELDWIDTHS "5" # assuming 5 is the width of the last field
next
}
这将查看第一行上的字段,并通过计算第二个到最后一个字段的后续字段的位置之间的差异来计算字段宽度。我假设最后一个字段的宽度是 5,但我认为你可以在那里放一个大数字,它将与剩下的内容一起使用。
我们需要在名称之前和之后查找空格,以确保我们找不到NAME
内部OWNER_NAME
(或者如果有一个名为 的字段OWNER
),而是匹配整个字段(我们还需要附加一个空格以$0
确保我们可以匹配即使末尾没有空格)。
您可以更喜欢,以便可以按字段名称查询而不是仅匹配$3
,但我将把它留给您。
答案3
可能最简单的方法是首先通过“想法价值为零,然后扔掉行”...或更多”来过滤行:
grep 'Ideas worth zero' | grep -v 'Ideas worth zero or more'
并从该管道中获取数字,输入:
cut -d' ' -f1 | tr -d ']['
这会剪切第一个字段(由空格分隔)并删除方括号。
最好的是,如果您可以稍微更改文件格式,使其带有适当的字段分隔符。
答案4
这可以帮助您:
function my_command () {
sed -n $(cut -b22-48 1.txt |
grep -n "$1"' *$' |
cut -f1 -d: )p 1.txt \
| cut -d' ' -f1 | tr -d ']['
}
它仅从输入中剪切相关列,搜索字符串出现的行号,然后获取该行并仅保留第一列中的数字。