[英]awk - take a random line from one file, and combine it with lines from another file, output to third file
[英]combine awk commands output of multiples searches display in one line
我的輸入如下
<connection name="test1" transport="tcp">
<LPort>host1:11111</hostPort>
<hostPort>host1:11111</hostPort>
<abcd> 1234
<connection name="test2" transport="tcp">
<hostPort>host2:22222</hostPort>
<GPort>host1:12111</hostPort>
<connection name="xyz1" transport="tcp">
<hostPort>host3:33333</hostPort>
<FPort>host1:12113</hostPort>
<efgi> 5678
<connection name="xyz2" transport="tcp">
<LPort>host1:12234</hostPort>
<hostPort>host4:4444</hostPort>
我希望我的投入如下:
test1 host1 1111
test2 host2 2222
xyz1 host3 3333
xyz2 host4 4444
為了解決這個問題,這就是我要做的,而且有效。 但是在我看來,必須有一個更好,更簡單的方法來實現,因為我沒有包括整個邏輯(數組)。 但是當我在文件中進行多次搜索時,我已經使用了很多這種方法,並且可以正常工作。 我嘗試使用&&命令組合awk命令,但失敗了。
以下是我的代碼和邏輯的一部分:1)處理文件2)擺脫多余的字符並用空格替換使用sed 3)我獲取所需的值並分配給數組值使用awk請注意,我未包括其余部分的邏輯(但它的工作原理)簡而言之,我做了一個while循環,然后將值分配給2或3數組,並將它們打印在同一行上以獲得所需的輸出
cat file | grep -A5 connection | sed s'/[:="><]/ /g' | awk '/name/ {print $3}'
cat file | grep -A5 connection | sed s'/[:="><]/ /g' | awk '/hostPort/ {print $2 " " $3}'
如果可能,請提供一種替代解決方案,該解決方案不涉及使用sed / awk或其他任何方式將搜索條件存儲在數組中?
如果您可以提供解決方案,請提供每個選項的詳細信息; 如果你可以的話。
謝謝
使用單sed方法:
sed -n '/<connection/{N;N; s/<connection name="\([^"]*\)".*<hostPort>\([^:]*\):\([^<]*\).*/\1 \2 \3/p}' file
輸出:
test1 host1 11111
test2 host2 22222
xyz1 host3 33333
xyz2 host4 4444
N;N;
-將接下來的2行添加到模式空間(包括換行符)
connection name="\\([^"]*\\)
-捕獲連接名稱
<hostPort>\\([^:]*\\):\\([^<]*\\)
-捕獲主機名和端口號
強制性提醒:假設您的輸入是格式正確的XML,那么使用XML解析器將提供更可靠的解決方案(請參閱底部)。
這是一個單一實用的awk
解決方案:
awk -v RS= -F '<connection name="|<hostPort>' '
{
sub(/".*/, "", $2)
split($3, tokens, /[:<]/)
printf "%-6s %s %s\n", $2, tokens[1], tokens[2]
}
' file
-v RS=
告訴awk
將輸入按段落拆分成記錄,其中一段是非空行。
-F '<connection name="|<hostPort>'
通過出現<connection name="
或( |
) <hostPort>
將每個段落分成多個字段,因此感興趣的數據將位於第二和第三字段的開頭 ( $2
和$3
)。
sub(/".*/, "", $2)
從字段2中刪除第一個"
之后的所有內容,實際上僅保留連接名稱。
split($3, tokens, /[:<]/)
通過出現:
和<
將第三個字段拆分為令牌數組,從而在第一個數組元素中生成主機名,在第二個數組元素中生成端口。
printf "%-6s %s %s\\n", $2, tokens[1], tokens[2]
打印輸出行,將連接名稱用空格右擊至少6個字符,如示例輸出所示; 如果只想用一個空格分隔輸出字段,則只需省略-6
。
xmllint
已預先安裝在某些平台上 :
sudo apt-get install libxml2-utils
xmllint
支持XPath 1.0查詢,但實際上它無法控制輸出格式 。 按需安裝替代方案-優於xmllint
:
xmlstarlet
功能強大且靈活,支持多種操作。
macOS :通過Homebrew用brew install xmlstarlet
sudo apt-get install xmlstarlet
xidel
需要手動下載和安裝 ,但其功能和靈活性彌補了這一不便。
支持Linux , macOS和Windows
以下是與上面列出的3個實用程序形成對比的解決方案 。
假定以下格式良好的XML文檔包含在file
-請注意<connection>
元素現在如何包含在單個頂級<doc>
元素中:
<doc>
<connection name="test1" transport="tcp">
<LPort>host1:11111</LPort>
<hostPort>host1:11111</hostPort>
<abcd>1234</abcd>
</connection>
<connection name="test2" transport="tcp">
<hostPort>host2:22222</hostPort>
<GPort>host1:12111</GPort>
</connection>
<connection name="xyz1" transport="tcp">
<hostPort>host3:33333</hostPort>
<FPort>host1:12113</FPort>
<efgi>5678</efgi>
</connection>
<connection name="xyz2" transport="tcp">
<LPort>host1:12234</LPort>
<hostPort>host4:4444</hostPort>
</connection>
</doc>
xmllint
解決方案: xmllint
缺乏對查詢結果格式的控制,因此需要一個簡單的awk
helper命令:
echo 'cat //connection/@name | //hostPort/text()' | xmllint --shell file | awk -F\" '
NR % 2 { next } # skip separator lines
NR % 4 == 2 { conn = $2; next } # save connnection name
{
split($0, tokens, ":")
printf "%-6s %s %s\n", conn, tokens[1], tokens[2]
}
'
xmlstarlet
解決方案: xmlstarlet
的sel
子命令通過將選項轉換為后台的XLST模板來支持非常靈活的提取:
xmlstarlet sel -t -m '//connection' -v 'str:align(@name, " ")' \
-o ' ' \
-c 'str:replace(hostPort, ":", " ")' -n file
xidel
解決方案: xidel
非常靈活,不僅支持XML,而且還支持HTML和JSON。
盡管它不支持XLST,但它支持XQuery ,它是具有類似XSLT功能的XPath的超集,可實現強大的轉換。 給雷諾戴上帽子的提示。
據我所知,沒有填充功能,因此,使用了-簡單的-輔助awk
命令:
xidel file -q --xquery \
'for $c in //connection return concat($c/@name, " ", replace($c/hostPort, ":", " "))' |
awk '{ printf "%-6s %s %s\n", $1, $2, $3 }'
也就是說,XQuery甚至支持用戶定義的函數,因此您可以編寫自己的填充函數:
xidel -q file --xquery '
declare function pad($s as xs:string?) as xs:string
{
substring(concat($s, " "), 1, 6)
}
for $c in //connection return concat(pad($c/@name), " ", replace($c/hostPort, ":", " "))
'
合並空白行分隔的塊並使用反向引用從每個塊中提取所需的值:
sed '${/^$/!{H;s/.*//;};};/^$/!{H;d;};/^$/{x;s/^\n<connection name="\([^"]*\)".*<hostPort>\([^:]*\):\([^<]*\).*/\1 \2 \3/;};' file
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.