Text-Processing

如何從一長串字元串組合中找到包含各種字元串的所有文件?

  • February 1, 2017

我對命令行工具(使用我的 Mac OSX 終端)仍然很陌生,希望我沒有錯過其他地方的答案,但我已經搜尋了幾個小時。

我有一個包含 3 個字元串的 200 個組合的文本文件(我們稱之為 strings.txt)。[編輯 2017/01/30 ] 前五行如下所示:

"surveillance data" "surveillance technology" "cctv camera"
"social media" "surveillance techniques" "enforcement agencies"
"social control" "surveillance camera" "social security"
"surveillance data" "security guards" "social networking"
"surveillance mechanisms" "cctv surveillance" "contemporary surveillance"

請注意,我可以將 strings.txt 更改為任何其他格式,只要第 1 行中的 bigrams/ 2 詞片語(如監視數據)保持在一起。(這意味著我可以在必要時刪除引號,至於下面@MichaelVehrs 的回答)。

現在我想在一個包含 800 多個文件的目錄中搜尋至少包含一個字元串組合的文件(文件中的任何位置)。我最初的想法是使用 egrep 和這樣的模式文件:

egrep -i -l -r -f strings.txt file_directory

但是,如果每行有一個字元串,我只能讓它工作。這是不可取的,因為我需要辨識的文件包含給定模式的所有三個字元串。有沒有辦法在 grep 模式文件中添加某種 AND 運算符?還是有另一種方法可以使用其他功能/工具來實現我想要的?非常感謝!

編輯 2017/01/30

下面@MichaelVehrs 的回答非常有幫助;我將其編輯為以下內容:

while read one two three four five six
do grep -ilFr "$one $two" *files* | xargs grep -ilFr "$three $four" |  xargs grep -ilFr "$five $six"
done < *patternfile* | sort -u

當模式文件包含不帶引號的字元串時,此答案有效。可悲的是,它似乎只匹配模式文件第一行的模式。有誰知道為什麼?

編輯 2017/01/29

之前已經詢問過關於 grepping 多個值的類似問題,但我需要AND邏輯來匹配其他文件中模式文件 strings.txt 中的三個字元串組合之一。我意識到 strings.txt 的格式可能必須更改才能使匹配工作,並希望得到建議。

由於agrep您的系統中似乎不存在,因此請查看基於 sed 和 awk 的替代方案,以通過本地文件讀取的模式應用 grep 和操作。

PS:由於您使用 osx,我不確定您擁有的 awk 版本是否支持波紋管使用。

awk可以在這種用法中使用多個模式的 AND 操作來模擬 grep:

awk '/pattern1/ && /pattern2/ && /pattern3/'

所以你可以從這個轉換你的模式文件:

$ cat ./tmp/d1.txt
"surveillance data" "surveillance technology" "cctv camera"
"social media" "surveillance techniques" "enforcement agencies"
"social control" "surveillance camera" "social security"
"surveillance data" "security guards" "social networking"
"surveillance mechanisms" "cctv surveillance" "contemporary surveillance"

對此:

$ sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' ./tmp/d1.txt
/surveillance data/ && /surveillance technology/ && /cctv camera/
/social media/ && /surveillance techniques/ && /enforcement agencies/
/social control/ && /surveillance camera/ && /social security/
/surveillance data/ && /security guards/ && /social networking/
/surveillance mechanisms/ && /cctv surveillance/ && /contemporary surveillance/

PS:您可以通過使用 將輸出重定向到另一個文件>anotherfileend ,或者您可以使用該sed -i選項在相同的搜尋詞模式文件中進行就地更改。

然後你只需要用這個模式文件中的 awk 格式的模式來提供 awk :

$ while IFS= read -r line;do awk "$line" *.txt;done<./tmp/d1.txt #d1.txt = my test pattern file

您也不能通過在原始模式文件的每一行中應用 sed 來轉換原始模式文件中的模式,如下所示:

while IFS= read -r line;do 
 line=$(sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' <<<"$line")
 awk "$line" *.txt
done <./tmp/d1.txt

或作為單線:

$ while IFS= read -r line;do line=$(sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' <<<"$line"); awk "$line" *.txt;done <./tmp/d1.txt

上面的命令在我的測試文件中返回正確的 AND 結果,如下所示:

$ cat d2.txt
This guys over there have the required surveillance technology to do the job.
The other guys not only have efficient surveillance technology, but they also gather surveillance data by one cctv camera.

$ cat d3.txt
All surveillance data are locked.
All surveillance data are locked and guarded by security guards.
There are several surveillance mechanisms (i.e cctv surveillance, contemporary surveillance, etv)

結果:

$ while IFS= read -r line;do awk "$line" *.txt;done<./tmp/d1.txt
#or while IFS= read -r line;do line=$(sed 's/" "/\/ \&\& \//g; s/^"/\//g; s/"$/\//g' <<<"$line"); awk "$line" *.txt;done <./tmp/d1.txt
The other guys not only have efficient surveillance technology, but they also gather surveillance data by one cctv camera.
There are several surveillance mechanisms (i.e cctv surveillance, contemporary surveillance, etv)

更新:

上述 awk 解決方案列印匹配 txt 文件的內容。

如果要顯示文件名而不是內容,請在必要時使用以下 awk:

awk "$line""{print FILENAME}" *.txt

我會使用perl,例如:

perl -MFile::Find -MClone=clone -lne '
 # parse the strings.txt input, here looking for the sequences of
 # 0 or more characters (.*?) in between two " characters
 for (/"(.*?)"/g) {
   # @needle is an array of associative arrays whose keys
   # are the "strings" for each line.
   $needle[$n]{$_} = undef;
 }
 $n++;

 END{
   sub wanted {
     return unless -f; # only regular files
     my $needle_clone = clone(\@needle);
     if (open FILE, "<", $_) {
       LINE: while (<FILE>) {
         # read the file line by line
         for (my $i = 0; $i < $n; $i++) {
           for my $s (keys %{$needle_clone->[$i]}) {
             if (index($_, $s)>=0) {
               # if the string is found, we delete it from the associative
               # array.
               delete $needle_clone->[$i]{$s};
               unless (%{$needle_clone->[$i]}) {
                 # if the associative array is empty, that means we have
                 # found all the strings for that $i, that means we can
                 # stop processing, and the file matches
                 print $File::Find::name;
                 last LINE;
               }
             }
           }
         }
       }
       close FILE;
     }
   }
   find(\&wanted, ".")
 }' /path/to/strings.txt

這意味著我們最小化了字元串搜尋的次數。

在這裡,我們逐行處理文件。如果文件相當小,您可以將它們作為一個整體進行處理,這將簡化一點並可能提高性能。

請注意,它確實希望列表文件位於:

"surveillance data" "surveillance technology" "cctv camera"
"social media" "surveillance techniques" "enforcement agencies"
"social control" "surveillance camera" "social security"
"surveillance data" "security guards" "social networking"
"surveillance mechanisms" "cctv surveillance" "contemporary surveillance"

格式,每行有一個數字(不必是 3)帶引號(帶雙引號)的字元串。帶引號的字元串本身不能包含雙引號字元。雙引號字元不是正在搜尋的文本的一部分。也就是說,如果列表文件包含:

"A" "B"
"1" "2" "3"

這將報告目前目錄及以下所有正常文件的路徑

  • A和_B
  • 或(不是排他性的或)全部123

在他們的任何地方。

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