在bash中提取所有匹配的子字符串

时间:2009-01-23 18:36:22

标签: bash shell

在bash中寻找解决方案(将成为更大脚本的一部分)。

给定一个包含表格信息的变量

diff -r efb93662e8a7 -r 53784895c0f7 diff.txt
--- diff.txt Fri Jan 23 14:48:30 2009 +0000
+++ b/diff.txt Fri Jan 23 14:49:58 2009 +0000
@@ -1,9 +0,0 @@ 
-diff -r 9741ec300459 myfile.c 
---- myfile.c Thu Aug 21 18:22:17 2008 +0000 
-+++ b/myfile.c Thu Aug 21 18:22:17 2008 +0000 -@@ -1,4 +1,4 @@ 
-  int myfunc() 
-  { 
--     return 1; 
-+     return 10; 
-  }

我希望将两个(此处为diff.txt和myfile.c,但未来的情况不会限于此数字)文件名提取为“edited:filename1 filename2 ... filenameN”形式的字符串。

为了澄清,我希望将多个匹配的文件名提取为字符串。

  • 命令“$(expr”$ editing“:'。* --- [[:space:]] \([[:graph:]] * \)[[:space:]]')”返回最后一个文件名正确,但不是以前的实例。

编辑:要求能够识别已编辑的文件名(可能包括空格),即“---”之后和“周五/周四......”之前出现的文件名。

感谢您的帮助(以及迄今为止许多人的回复)。

4 个答案:

答案 0 :(得分:3)

仅使用bash内置函数的解决方案,没有外部程序:

res="edited: "; var="${var#* --- } --- "
while test -n "$var";do res="$res ${var%% *}"; var="${var#* --- }";done
echo "$res"

它迭代所有出现的“---”。 诀窍是首先从一开始就修剪garbarge来准备字符串 (直至第一---) 并在末尾追加“---”,以便在while循环中具有更简单的逻辑。

这是通过使用bash最有用的功能,#和%来修剪字符串

答案 1 :(得分:1)

我建议使用外部工具 - 这是perl的一种方式:

$(echo "$variable" | perl -e 'print "edited:"; while (<>) { while (/--- (\S+)/g) { print " $1"; } }')

我确信它可以更优雅地完成,但我现在想不出一种不会采取更实质性计划的方法。

答案 2 :(得分:1)

这是一个简单,有效的解决方案:

txt=$(cat)
str="edited: "

for word in $txt; do
        if echo $word | grep -qi '^[a-z0-9-_]*\.[a-z]*$'; then
           str="$str $word"
        fi
done

echo $str

运行它:

anton@CAPTAIN-FALCON ~/Desktop
$ bash sol.sh
diff -r efb93662e8a7 -r 53784895c0f7 diff.txt --- diff.txt Fri Jan 23 14:48:30 2
009 +0000 +++ b/diff.txt Fri Jan 23 14:49:58 2009 +0000 @@ -1,9 +0,0 @@ -diff -r
 9741ec300459 myfile.c ---- myfile.c Thu Aug 21 18:22:17 2008 +0000 -+++ b/myfil
e.c Thu Aug 21 18:22:17 2008 +0000 -@@ -1,4 +1,4 @@ - int myfunc() - { -- return
 1; -+ return 10; - }
edited: diff.txt diff.txt myfile.c myfile.c

编辑:用grep徘徊了一段时间导致了以下脚本,但我开始怀疑纯粹的bash是否适合这项工作......似乎会有在许多极端情况下你会错过一些文件或获得错误的文件名。

#! /bin/bash

rawFiles=`cat | grep -ioz ' -* [a-z0-9-_\ ]*\.[a-z]*'`

for file in $rawFiles; do
   if ! echo $file | grep -q '^-*$'; then
      files="$files${file} "
   fi
done

echo "edited: $files"

答案 3 :(得分:0)

您可以在设置$ editing之前执行操作 - 那么您可能仍然有换行符吗?

然后也许一些sed能够提取文件名。