簡體   English   中英

使用 grep 搜索文件並且只輸出部分行

[英]searching files with grep and only outputting parts of lines

我正在查看日志文件並試圖在我的最終文件中獲得不那么混亂的輸出。 如果我 grep 一個值,我想格式化輸出以刪除除日期和 url 之外的任何內容。

例如這里是文件的一行。

9 月 25 日 08:07:51 10.20.30.40 FF_STUFF[]: 1545324890 1 55.44.33.22 10.9.8.7 - 10.60.154.41 http://website.com 0 BYF 0 - 0 0 0 允許 0 sqm.microsoft.com - [-] sqm.microsoft.com - - 0

我想做一個 grep 或必要時更好的命令,以輸出到僅列出粗體條目的 .txt 文件。 基本上列出日期和 URL。 那么我如何告訴它列出包括空格在內的前 15 個字符,然后找到第一個 http/https 並列出所有內容直到第一個空格? 每行的長度或任何性質都不相同,所以我不能只按字符位置。

所以我的輸出將是

9 月 25 日 08:07:51 http://website.com

謝謝你。

您不能在grep輕松使用-o選項,因為您有兩個模式,由可變數量的字符分隔(並且-o將打印完整的匹配部分)。

如果您只想提取 URL,這就足夠了:

$ grep -oE 'https?:[^ ]+' file
http://website.com

但是要提取日期和 URL,可能最簡單的解決方案是使用GNU awk

$ awk '{ match($0, /https?:[^ ]+/, url); print $1, $2, $3, url[0]; }' file
Sep 25 08:07:51 http://website.com

打印前三個字段( $1$3 ,空格分隔),然后使用match()搜索 URL(假設它不包含空格,即空格字符始終正確轉義;作為+%20 ),然后打印找到的第一個 URL(日期之后)。

如果您有POSIX awk (或使用--posix標志調用gawk ),則解決方案會稍微冗長一些,因為 POSIX match()不支持將匹配的部分保存到數組中(第三個參數, url )和找到匹配項時,您必須使用substr()顯式提取 URL:

$ awk '{ match($0, /https?:[^ ]+/); print $1, $2, $3, substr($0, RSTART, RLENGTH); }' file
Sep 25 08:07:51 http://website.com

為了補充@randomir 的回答,我們還可以使用sed

$ sed 's/\(.\{15\}\).*\(https\?:\/\/[^ ]\+\).*/\1 \2/' < input.txt > output.txt

此模式假定前 15 個字符組成日期並且 URL 不包含空格。 它適用於httphttps URL。


編輯- 解決注釋 - 為了學習,我們還可以調用sed來執行行匹配操作,如grep

sed -n '/10\.45\.19\.151/p' < input.txt

...將輸出input.txt中包含 IP 地址10.45.19.151任何行。 -n選項抑制每一行的輸出。 我們將此選項與p命令結合使用以僅打印與模式匹配的行。

我們可以將此方法與第一個命令合並以“grep”行使用單個命令轉換它們:

sed -n '/<line-match-pattern>/ s/<...>/<...>/ p' < input.txt

...將僅選擇匹配<line-match-pattern> ,執行替換並輸出結果。 為了說明,這里有一個使用評論中提供的信息的示例:

sed -n '/10\.45\.19\.151/ s/\(.\{15\}\).*\(https\?:\/\/[^ ]\+\).*/\1 \2/ p' \
    < messages-20171001 \
    > /backup/mikesanders-fwlog-10012017.txt
awk '{match($0,/http[^com]*/);print $1,$2,$3,substr($0,RSTART,RLENGTH+3)}'  Input_file

以上代碼說明:

awk '{
match($0,/http[^com]*/);                  ##Using match default utility of awk where I am searching for regex where it will look for string http till string com comes.
print $1,$2,$3,substr($0,RSTART,RLENGTH+3)##Now printing the 1st, 2nd and 3rd column which are date and time in current line and printing sub string of current line where it should start substring from the value of RSTART till value of RLENGTH(which will be http complete URL actually). Now point to be noted here variables RSTART and RLENGTH are default variables of awk which will be set once a regex match is found in match utility of awk.
}
' Input_file                              ##Mentioning the Input_file name here.

您可以使用grep -o匹配您想要的每個行部分,然后重新組合 grep 返回的行:

$ grep -Eo '^.{15}|https?://[^ ]+' f | paste - -
Sep 25 08:07:51 http://website.com

請注意,在 FreeBSD 或 OSX 中,他們使用的舊版本 GNU grep (2.5.1) 有問題,因此需要更明確的日期識別:

$ grep -Eo '[A-Z][a-z]{2} ([0-9]{2}[ :]){3}[0-9]{2}|https?://[^ ]+' f | paste - -
Sep 25 08:07:51 http://website.com

FreeBSD 中的一種解決方法是使用bsdgrep ,它在功能上等同於 gnu grep 但沒有錯誤。 在 MacOS 中,可能需要使用 homebrew 或 macports 安裝替代方案 .. 或者只是在另一個答案中使用 POSIX awk 解決方案。

無論如何,在這兩種情況下,正則表達式都由兩個用 or-bar( | ,在https之前)連接的表達式組成。 第一個子表達式匹配您的日期,第二個子表達式匹配您的 URL。

只要輸入的每一行都包含匹配這兩個元素的文本,您應該從 grep 為每個日志條目獲得兩行輸出。 然后paste將它們重新組合成一行。

只有 1 個命令行,如:

msr -p my.log -t "^(.*?\\d+:\\d+:\\d+).*?(https?://\\S+).*" -o '$1 $2' -PIC > output.txt

  • 如果first 15 characters比模式"^(.*?\\d+:\\d+:\\d+)"更可靠:

    使用"^(.{15})"例如: -t "^(.{15}).*?(https?://\\S+).*"

  • 如果你想進一步過濾,比如包含一個 ip 10.9.8.7作為純文本( -x ):

    msr -p my.log -x 10.9.8.7 -t "^(.*?\\d+:\\d+:\\d+).*?(https?://\\S+).*" -o '$1 $2'

  • 如果必須包含更多 IP,如10.9.8.7 10.9.8.8 10.9.8.9 ,或進一步處理:

    msr -p my.log -t "^(.*?\\d+:\\d+:\\d+).*?(https?://\\S+).*" -o '$1 $2' -PAC | msr -t "10\\.9\\.8\\.[7-9]" -PAC > output.txt

msr.exe / msr.gcc*我打開的項目中用於此類 ETL 類似工作(加載 -> 提取 -> 轉換或替換文件)的單個 exe 工具,大約 1.6MB,無依賴項,具有跨平台版本以及x86 / x64版本。

  • 遞歸加載文件 ( -r ) 並過濾目錄名、文件名、時間、大小,例如:

    -r -p dir1,dirN,file1,fileN -f "\\.(log|txt)$" --w1 2017-09-25--nf "excluded-files" --nd "excluded-directories" , --s1 1.5MB --s2 30MB , --w2 "2017-09-30 22:30:50"

  • sedawk不同,通過常規Regex提取,與C++ / C# / Java / Scala / 等完全相同:

    -t "^(.*?\\d+:\\d+:\\d+).*?(https?://\\S+).*"忽略大小寫:添加-i like: -i -t-it

  • 轉換輸出,如:

    • -o '$1 $2'適用於 Linux 或 Windows 上的Cygwin / Powershell
    • -o "$1 $2"用於 Windows CMD console window*.bat / *.cmd文件。

請參閱以下屏幕截圖: 提取日志並轉換輸出

如果你在 Linux 上,你可以運行msr.gcc48msr-i386.gcc48它是 32 位機器。 直接運行exe就可以看到用法和例子,也可以看網上的性能對比文檔(Linux系統工具grep和Windows系統工具findstr ),內置文檔如:CentOS上的msrWindows上的彩色生動演示

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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