我有一個這種格式的文件:
[#] 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 ']['
}
它僅從輸入中剪切相關列,搜尋字串出現的行號,然後取得該行並僅保留第一列中的數字。