Bash

awk 取文件名而不是 for 循環中的文件

  • August 20, 2018

好的,所以我需要使用 awk 從某個文件中提取某個列,將其放入一個數組中然後對其進行排序,然後我還需要使用 awk 在這些提取的排序列中查找一些值,但現在我有我的 for 循環的一些問題:

for var in $1 $2
do
myarr=($(awk -v row=$3 -F';' '$row!="" {print $row}' $var))
sorted_array=( $( printf "%s\n" "${myarr[@]}" | sort -n ) )
echo "${sorted_array[@]} $var"
done

輸出是:

dbdump.csv
dbdump2.csv

這是我要從中提取列的兩個 csv 文件的名稱。如果有人可以提供某種解決方案,將不勝感激,因為我需要這個腳本來搜尋東西。另外,如果您可以建議一種算法上更快的方法,請這樣做,這只是我學習一些 bash 腳本並嘗試將一些程式碼放在一起。

輸入文件包含這樣的記錄,我有兩個在第 3 列中沒有匹配值的文件(這就是我的經理所說的):

1101590479;Frank Haemers;;20060310;1;RESI;;01;06;0007;0000000000;;CRM000;
1101590473;Van KetsmJan;;20060310;2;PROF;;01;08;;0000000000;75;CRM000;0686143950

這兩個文件有大約 500 萬條記錄。我有另一個具有一定數量模式的文件,必須查找這兩個巨大的 csv 文件,如果其中一個模式在任何一個文件中匹配,我需要輸出到另一個文件中,例如:

echo "$pattern has been found in $file"

我需要對我的模式文本文件中找到的所有模式執行此操作

編寫 shell 腳本時,最好先指定已驗證的變數,最後指定文件名,這樣您就可以改變指定的文件數量。在您的情況下,您有列號、其中包含模式的文件以及兩個(或更多)文件名來處理。所以,開始你的 Bash 腳本

#!/bin/bash
if [ $# -lt 2 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
   echo ""
   echo "Usage: $0 [ -h | --help ]"
   echo "       $0 COLUMN PATTERNFILE [ FILE(s) ... ]"
   echo ""
   exit 0
fi

上面的if子句使用舊式 POSIX shell 格式,並且可以在dash(和其他 POSIX shell)以及大多數舊式shshell 中工作。目的是如果使用者沒有指定任何命令行參數,或者只是一個-hor --help,腳本只會列印一個簡短的幫助文本。

順便說一句,您應該擴展幫助文本,因為在您忘記編寫它之後,它可以更容易地在兩三個月內找出它的作用。(一直發生在我身上,而且我有很多這樣的小腳本,所以我發現這種做法非常值得付出一點努力。)

接下來,提取所需的參數(上面只有一個),並將shift它們取出,以便我們可以使用"$@"來引用命令行中指定的所有文件名:

column=$1
patternfile="$2"
shift 2

請注意,我喜歡在我想在 shell 中擴展的內容周圍加上雙引號,即使在沒有明確必要的情況下也是如此。這是因為我在使用 shell 腳本時遇到的大多數實際問題都是由於忘記引用副檔名,而這是必要的。這種做法很容易記住,除了用令人討厭的鼻音有一些無所不知的評論“你實際上不需要那些雙引號”之外,它們沒有害處。

然後讓我們awk用來處理輸入文件:

awk -v column=$column \
 'BEGIN {
      RS = "[\t\v\f ]*(\r\n|\n\r|\r|\n|)[\t\v\f ]*"
      FS = "[\t\v\f ]*;[\t\v\f ]*"
  }

上面第一行末尾的反斜杠只是告訴 shell 命令在下一行繼續。另請注意,沒有關閉單引號',因此下面的行實際上是我們提供給的命令行字元串參數的延續awk

awk 中的BEGIN規則在處理文件之前執行。上面RS將記錄分隔符設置為任何換行約定,並在每行中包含任何前導或尾隨空格。類似地,欄位分隔符是一個分號,但包括它周圍的任何空格。因此,a ; b有兩個欄位,第一個欄位a和第二個欄位b都沒有任何空格。

我使用以下習慣用法來跟踪正在處理的輸入文件:

   FNR==1 { ++filenum }

如果只是意味著對於我們處理的每個輸入文件中的第一條記錄,我們會增加filenum變數。增加一個未初始化的變數與增加一個零相同,所以我們得到1第一個輸入文件,依此類推。

我們只想記住第一個輸入文件中每一行的內容,我們的模式文件:

   filenum==1 { pattern[$0] }

awk 數組是關聯的,所以我們可以只使用關聯數組來保存已知模式。上面,我們使用了一個有趣的 awk 功能來發揮我們的優勢:如果您嘗試訪問一個尚不存在的關聯數組條目,則 awk 會創建它!

對於其餘的文件,我們只檢查欄位$column(提供給 awk 變數中的 awk 腳本column)是否(完全)匹配第一個文件中看到的任何模式,如果是,我們列印整個記錄:

   filenum > 1 && ($column in pattern) { printf "%s\n", $0 }

以上,$column與 shell 腳本相比具有不同的含義。這裡,column是一個變數,並$column擴展為column目前記錄中第 ’th 欄位的值(然而,第 0 列是整個記錄)。foo in array語法是用於檢查是否array包含 key的awkism foo。因此,總的來說,對於第二個和更多輸入文件,如果column第一個輸入文件中列出了第 ’th 欄位值,則列印記錄。到標準輸出。

我們還在awk命令行參數字元串中,需要關閉單引號字元串。我們還想為它提供文件名:

   ' "$patternfile" "$@"

這結束了這個 awk scriptlet。

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