如何使正则表达式与文件路径匹配?

时间:2016-05-22 03:43:54

标签: regex bash grep

我一直在玩这个命令大约一两个小时,我担心我可能失去了客观性。 目标是仅匹配给予bash的相对文件路径。

第一条相对路径../some/file/path

第二条相对路径为..../some/file/path

" / some / file / path"的长度是任意的。

我一直在grep内使用bash来尝试找出如何在我的脚本中实现它,以便我可以将其扩展到它的绝对文件路径所以./some/file/path../some/file/path变为/the/absolute/file/path;我已经弄清楚了。

我的问题是匹配相对路径。

我一直在使用的代码是

echo "../some/file/path" | egrep '\.{1}/?[[:graph:]]?+$'

echo "../some/file/path" | egrep '\.{2}/?[[:graph:]]?+$'

我已将问题缩小为

echo ".." | egrep '\.{2}'
只要出现2 + n次出现,

将匹配该点,不会出现预期的<2>次。当我将其更改为

时,会发生同样的事情
echo ".." | egrep '\.{1}' 

仍然会因某些原因而无法匹配。

最终的实现应该像这样工作

 41 _expand_relative_path () {
 42         if [[ "$1" =~ ^\.{1}/?[[:graph:]]?+$ ]]; then
 43                 echo "."
 44         elif [[ "$1" =~ ^\.{2}/?[[:graph:]]?+$ ]]; then
 45                 echo ".."
 46         else    
 47                 echo "$1"
 48         fi
 49 }

根据我的教科书,如果恰好n次出现,则说明符{n}将匹配前面的元素。但它并没有那样做!如果它是n次或更多次匹配!我做错了什么?

4 个答案:

答案 0 :(得分:4)

匹配相对路径的正则表达式不是以斜杠开头的:

^[^/].*

答案 1 :(得分:1)

^\.{1}/?[[:graph:]]?+$的问题是/已被指定为可选,并且以下[[:graph:]]字符类匹配任何可见,包括更多句点。此外,您已使用?+量化了您的角色等级,这意味着&#34;零或一次,占有欲&#34;:它无法匹配,但如果确实如此,则不会& #34;放弃&#34;是什么让这个模式的其余部分试图成功 - 可能不是你想要的那样。

当你说echo ".." | egrep '\.{2}'时,你所说的是&#34;字符串在某个时刻包含连续两个句点&#34; - 但这并不意味着它可以拥有更多的句号或其他任何内容,而不是没有^$锚定,这将限制完全且仅 两个时期。

正如其他人所说,任何不以/开头的路径都是相对的,因此^[^/].*有效。但是,如果您想要查找文本文件中包含其他文本的相对路径,这可能很有用:

(\.{1,2}(?:\/[[:alnum:]]*)*)

regex demo输出:

enter image description here

答案 2 :(得分:1)

echo ".." | egrep '\.{2}'
     只要有2 + n次出现,

就会匹配点,而不是2   按预期发生。

是的。默认情况下,grep会打印包含模式的行。任何包含两个以上连续点的线必然包含两个连续点,因此模式匹配。

  

当我将其更改为

时,会发生同样的事情
echo ".." | egrep '\.{1}' 
     

仍然会因某些原因而无法匹配。

同样的事情:字符串&#34; ..&#34;包含&#39;。&#39;因此它匹配模式。

现在考虑一下您的原始模式,'\.{2}/?[[:graph:]]?+$'

  1. 首先,观察它没有锚定到字符串的开头,因此它将匹配形式/foo/bar../baz(和其他)的绝对路径。您需要在模式中使用初始^来锚定它。
  2. 使用/量词可以在前导点可选后显示?。如果您的目标专门用于匹配第一个分段为..的路径,则不清楚为什么要这样做。我唯一能想到的是你想要匹配你的模式所具有的..本身的路径,但它接受了。
  3. 下一个片段是[[:graph:]]?+,这似乎是编写更标准[[:graph:]]*的奇怪方式。此外,您似乎依赖于[[:graph:]]将匹配/字符的事实,因此您可以将前面的可选/权限滚动到字符类中:'^\.{2}[[:graph:]]*$'
  4. 现在观察[[:graph:]] 匹配.。这现在解释了为什么原始模式匹配包含两个以上连续点的字符串:前两个由\.{2}匹配,没有任何内容与/?匹配,剩余的点(可能还有其他字符)由[[:graph:]]?+匹配。
  5. 最后,请考虑\.\.\.{2}更短更清晰,尤其是\. \.{1}更清晰。< / LI>

    当然,在他的回答中,@ Bohemian提供了匹配每个可能的相对路径的自然模式,但是如果你想要一个模式专门匹配第一个段为...的路径,包括那些没有其他段,没有尾随/的那些你可以试试这个:

    egrep '^\.{1,2}(/.*[^/])?$'
    
    • 它锚定在开头(^)和结尾($),因此它执行整行匹配(仅限)。
    • 匹配行必须以一个或两个点(\.{1,2}
    • 开头
    • 其他任何内容都是可选的((...)?),但如果存在该可选段,则它必须以/开头,并以不是/的字符结尾。中间可以是任何字符(.*)的任何数字,包括零。
    • 请注意,Unix文件和目录名称可以包含空格和非图形字符,因此在原始模式中使用[:graph:]会将其限制为可能路径的子集。

答案 3 :(得分:0)

对于Windows:^.*\\(?!.*\\)(.*)$

或Linux:^.*/(?!.*/)(.*)$

或两者兼有:

^.*(?:\\|/)(?!.*(?:\\|/))(.*)$

它与filename.extension.../path/filename.extension中的...\path\filename.extension匹配,因为它会检查\/的最后一次出现,然后从中检出每个字符那一点。