[英]In GNU Grep or another standard bash command, is it possible to get a resultset from regex?
考慮以下:
var="text more text and yet more text"
echo $var | egrep "yet more (text)"
應該可以將正則表達式的結果作為字符串: text
但是,我目前尚無辦法在bash中使用grep或其兄弟姐妹執行此操作。
在perl,php或類似的正則表達式引擎中:
$output = preg_match('/yet more (text)/', 'text more text yet more text');
$output[1] == "text";
編輯:要詳細說明為什么我不能只使用多個正則表達式,最后我將擁有一個包含多個正則表達式的正則表達式(如下圖所示),因此我需要能夠全部使用它們。 這也消除了使用超前/向后看的選項(因為它們都是可變長度的)
egrep -i "([0-9]+) +$USER +([0-9]+).+?(/tmp/Flash[0-9a-z]+) "
直接根據lsof輸入的示例輸入(此輸入數據的$ USER替換為“ j”):
npviewer. 17875 j 11u REG 8,8 59737848 524264 /tmp/FlashXXu8pvMg (deleted)
npviewer. 17875 j 17u REG 8,8 16037387 524273 /tmp/FlashXXIBH29F (deleted)
最終目標是每行cp /proc/$var1/fd/$var2 ~/$var3
,最終“下載” Flash文件(Flash曾經存儲在/ tmp中,但它們將其刪除)
到目前為止,我已經:
#!/bin/bash
regex="([0-9]+) +j +([0-9]+).+?/tmp/(Flash[0-9a-zA-Z]+)"
echo "npviewer. 17875 j 11u REG 8,8 59737848 524264 /tmp/FlashXXYOvS8S (deleted)" |
sed -r -n -e " s%^.*?$regex.*?\$%\1 \2 \3%p " |
while read -a array
do
echo /proc/${array[0]}/fd/${array[1]} ~/${array[2]}
done
它會截斷要返回的第一個值的前幾位,而我對sed並不十分了解,以了解出了什么問題。
下載Flash 10.2+視頻(包括加密的視頻)的最終結果:
#!/bin/bash
lsof | grep "/tmp/Flash" | sed -r -n -e " s%^.+? ([0-9]+) +$USER +([0-9]+).+?/tmp/(Flash[0-9a-zA-Z]+).*?\$%\1 \2 \3%p " |
while read -a array
do
cp /proc/${array[0]}/fd/${array[1]} ~/${array[2]}
done
編輯:查看我的其他答案,以獲得更簡單的僅bash解決方案。
因此,這里的解決方案使用sed
獲取正確的組並將其拆分 。 您以后仍然必須使用bash來閱讀它們。 (以這種方式,它僅在組本身不包含任何空格的情況下才起作用-否則,我們必須通過將$IFS
設置為此值來使用另一個分隔符和補丁read
。)
#!/bin/bash
USER=j
regex=" ([0-9]+) +$USER +([0-9]+).+(/tmp/Flash[0-9a-zA-Z]+) "
sed -r -n -e " s%^.*$regex.*\$%\1 \2 \3%p " |
while read -a array
do
cp /proc/${array[0]}/fd/${array[1]} ~/${array[2]}
done
請注意,我必須調整您的最后一個正則表達式組以允許使用大寫字母,並在開頭添加一個空格以確保捕獲整個數字塊。 另外,這里\\b
(字數限制)也可以使用。
啊,我忘了提到您應該將文本通過管道傳遞到此腳本,如下所示:
./grep-result.sh < grep-result-test.txt
(前提是您的文件是這樣命名的)。 相反,您可以在sed
調用之后(在|
之前)添加< grep-result-test
,或在行前添加cat grep-result-test.txt |
。
它是如何工作的?
sed -r -n
以擴展正則表達式模式調用sed,並且不會自動打印任何內容。 -e " s%^.*$regex.*\\$%\\1 \\2 \\3%p "
給出sed程序,它由單個s
命令組成。
%
而不是普通的/
作為參數分隔符,因為/
出現在正則表達式中,並且我不想對其進行轉義。 要搜索的正則表達式以^.*
為前綴,並以.*$
結尾,以捕獲整行(並避免打印其余行)。
請注意,此.*
貪婪,因此我們必須在正則表達式中插入一個空格,以避免它也捕獲第一個數字組的開頭。
p
標志指示替換后打印出模式空間。 由於我們抓住了整行,因此模式空間僅包含替換文本。 因此,您的示例輸入的sed輸出是這樣的:
5 11 /tmp/FlashXXu8pvMg 5 17 /tmp/FlashXXIBH29F
顯然,這對於重用更為友好。
現在,我們將此輸出通過管道傳遞給while循環。
read -a array
從標准輸入(由於管道的緣故,是sed的輸出)中讀取一行,將其拆分為單詞(在空格,制表符和換行符處),並將這些單詞放入數組變量中。
我們還可以read var1 var2 var3
(最好使用更好的變量名),然后將前兩個單詞分別放在$var1
和$var2
,其余的則放在$var3
。
read
成功讀取一行(即不是文件末尾),則執行循環主體:
${array[0]}
被擴展到數組的第一個元素,並且類似地。 使用grep或從shell提示符/腳本調用的其他工具是不可能的,因為子進程無法修改其父進程的環境。 如果您使用的是bash 3.0或更高版本,則可以使用進程內正則表達式。 語法為perl-ish(=〜),可通過$ BASH_REMATCH [x]獲得匹配組,其中x是匹配組。
創建sed
解決方案后,我還想嘗試Mark建議的純bash方法。 對我來說,它工作得很好。
#!/bin/bash
USER=j
regex=" ([0-9]+) +$USER +([0-9]+).+(/tmp/Flash[0-9a-zA-Z]+) "
while read
do
if [[ $REPLY =~ $regex ]]
then
echo cp /proc/${BASH_REMATCH[1]}/fd/${BASH_REMATCH[2]} ~/${BASH_REMATCH[3]}
fi
done
(如果您對此表示支持,則應該考慮也對Marks答案進行支持,因為這本質上是他的想法。)
與之前相同:將要過濾的文本通過管道傳遞到此腳本。
它是如何工作的?
[[ ... ]]
特殊條件構造支持二進制運算符=~
,它將其右操作數(在參數擴展之后)解釋為擴展的正則表達式(就如我們所願),並與左操作數匹配反對。 (我們再次在前面添加了一個空格,以避免僅匹配最后一位。) [[ ... ]]
返回0(= true),並將與單個組匹配的部分(以及整個表達式)放入數組變量BASH_REMATCH
。 then
塊,然后在其中執行命令。 ${BASH_REMATCH[1]}
是對數組元素的數組訪問,該元素對應於第一個匹配組。 ( [0]
將是整個字符串。) 另一個注意事項:我的兩個腳本都接受多行輸入,並在匹配的每一行上工作。 不匹配的行將被忽略。 如果只輸入一行,則不需要循環, if read ; then ...
很簡單if read ; then ...
if read ; then ...
甚至read && [[ $REPLY =~ $regex ]] && ...
就足夠了。
echo "$var" | pcregrep -o "(?<=yet more )text"
好吧,對於您的簡單示例,您可以執行以下操作:
var="text more text and yet more text"
echo $var | grep -e "yet more text" | grep -o "text"
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.