簡體   English   中英

結合awk命令將搜索的輸出顯示在一行中

[英]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


可選閱讀:可在外殼腳本中使用的XML解析實用程序(CLI)

  • xmllint預先安裝某些平台上

    • macOS / FreeBSD / PC-BSD (可能是其他BSD變體)
    • 一些 Linux發行版: FedoraCentOS
    • 在其他產品上,可能有包裝。 例如,在Ubuntu上:
      sudo apt-get install libxml2-utils
    • 注意 :盡管xmllint支持XPath 1.0查詢,但實際上無法控制輸出格式
  • 按需安裝替代方案-優於xmllint

    • xmlstarlet

      • xmlstarlet功能強大且靈活,支持多種操作。

      • macOS :通過Homebrewbrew install xmlstarlet

      • Linux :可能會與您平台的軟件包管理器一起安裝; 例如,在基於Debian的發行版(如Ubuntu)上
        sudo apt-get install xmlstarlet
      • Windows :從sourceforge下載並手動安裝。
    • xidel

      • xidel需要手動下載和安裝 ,但其功能和靈活性彌補了這一不便。

      • 支持LinuxmacOSWindows


以下是與上面列出的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解決方案:

xmlstarletsel子命令通過將選項轉換為后台的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM