Awk

基於 ‘_’ 在 Bash 中拆分列

  • September 21, 2019

您好,我遇到了與這篇文章中的問題類似的問題

但由於我是 Bash 新手,而且我的文件有點不同,我無法修改並將答案應用於我的程式碼。

我有一個包含多列的 csv 文件(所有列都以逗號分隔),我要拆分的列如下所示:(輸入文件)

post_id
86680728811_272953252761568
86680728811_273859942672742
86680728811_281125741936891
86680728811_10150500662053812
_86680728811_10150500969563812
86680728811_10150501303143812
86680728811_305275689511038
_86680728811_10150501624593812
86680728811_10150501873973812
86680728811_145945585518261

我想提取第二個 ID 號(下劃線後面的那個)。請記住,有些列以數字開頭,有些以空格開頭,有些以“_”開頭。

我想要的輸出是添加兩個新列,每個列都包含由“_”分隔的 ID。第一行範例:

page ID             post ID 
86680728811         272953252761568

我嘗試使用正則表達式來讀取數字:

awk -F',' '{print $2} /(?<=_)[0-9]+/' FB_Dataset.csv

但到目前為止,我所嘗試的一切都沒有奏效。任何建議都會有所幫助。謝謝

這對你有用嗎?我將採用這種格式:

A B C post_id
a,b,c,86680728811_272953252761568
a,b,c, 86680728811_273859942672742
a,b,c,86680728811_281125741936891
a,b,c,86680728811_10150500662053812
a,b,c,_86680728811_10150500969563812
a,b,c,86680728811_10150501303143812
a,b,c,86680728811_305275689511038
a,b,c,_86680728811_10150501624593812
a,b,c, 86680728811_10150501873973812
a,b,c,86680728811_145945585518261

然後是命令

cat file | sed -Ee 's/(.*)post_id/\1page ID post I/' -e 's/,[_ ]/,/' -e 's/_/,/'

輸出:

A B C page ID post ID
a,b,c,86680728811,272953252761568
a,b,c,86680728811,273859942672742
a,b,c,86680728811,281125741936891
a,b,c,86680728811,10150500662053812
a,b,c,86680728811,10150500969563812
a,b,c,86680728811,10150501303143812
a,b,c,86680728811,305275689511038
a,b,c,86680728811,10150501624593812
a,b,c,86680728811,10150501873973812
a,b,c,86680728811,145945585518261

-E使用擴展正則表達式 (GNU),以便可以擷取組。


更改標題以添加page ID post ID擷取第一個組(.*)直到post_id,並將其替換為擷取的組\1page ID post ID

's/(.*)post_id/\1page ID post ID/'

從逗號後面的行中刪除前導空格和下劃線_,並將其替換為單個逗號。

sed 's/,[_ ]/,/'

_最後,用逗號替換下劃線。

sed 's/_/,/'

請注意,我刪除了cut不必存在的命令(這是我嘗試過的其他命令的提醒)

awk -F', *_?' -v OFS=, '
 NR==1 {
   for (i=1;i<=NF;i++) {
     if ($i == "post_id") {
       $i = "page ID" OFS "post ID";
       col=$1;
     };
   };
   print;
   next
 };

 {
   split($col,a,/_/);
   $col=a[1] OFS a[2];
   print;
 };
 ' FB_Dataset.csv

因為您顯示的欄位數據的格式不一致(有些以空格開頭,有些以下劃線開頭,也許有些兩者兼有),所以此awk腳本使用正則表達式, *_?(“逗號後跟零個或多個空格,並且可選後跟一個下劃線") 作為欄位分隔符 ( FS)。

它還將輸出欄位分隔符 ( OFS) 設置為逗號。

在讀取輸入時,它會以不同方式處理第一行(CSV 標題)和所有剩餘的行:

對於第一行 ( NR==1),它檢查每個欄位的值,查找字元串"post_id"。如果找到該字元串,它會更改該欄位的值,使其具有兩個新欄位名稱 (page IDpost ID),由OFS. 它還將該欄位的索引號儲存在變數col中以供以後使用。最後,它列印修改後的行。

這假定欄位名稱是唯一的,因為它們應該是有效的 CSV 文件。如果多個欄位具有 name ,它將無法正常工作post_id

對於剩餘的行,它使用下劃線 ( ) 字元作為分隔符將欄位拆分$col為數組。然後它將 $col 替換為該數組的前兩個元素,由. 然後它列印修改後的行。a``_``OFS

樣本輸入:

A,B,C,post_id,D,E,F
a,b,c,86680728811_272953252761568,d,e,f
a,b,c, 86680728811_273859942672742,d,e,f
a,b,c,86680728811_281125741936891,d,e,f

樣本輸出:

A,B,C,page ID,post ID,D,E,F
a,b,c,86680728811,272953252761568,d,e,f
a,b,c,86680728811,273859942672742,d,e,f
a,b,c,86680728811,281125741936891,d,e,f

在標題行中,該post_id欄位已被轉換為兩個欄位(page IDpost ID),而在 CSV 數據中,相應的欄位已被拆分為兩個欄位。

順便說一句,因為腳本在標題行中搜尋匹配的欄位名稱 ( post_id),所以它可以處理我們要拆分的欄位之前和/或之後的任意數量的欄位。有了這個樣本數據,發現第四個欄位包含了我們想要的名字,所以col=4


請注意,$i並且$col在 awk 中的含義與在 shell 中的含義不同。

  • 在 shell 中,它們表示名稱i和的變數col
  • awk中,它們的意思是“索引號等於變數i(或變數col)的值的欄位的值”。即它通過間接訪問欄位。

例如,如果i=1then$i表示“欄位 1 中的值”,則與$1.

例如,如果您需要對欄位編號執行算術運算,這很有用。在 awk 中,NF是一個自動創建的變數,包含目前輸入行的最後一個欄位的索引號。so$NF表示“最後一個欄位中的值”,$(NF-1)表示“倒數第二個欄位中的值”,依此類推。

引用自:https://unix.stackexchange.com/questions/542738