如何使用括号匹配模式而不是单个字母/数字?

如何使用括号匹配模式而不是单个字母/数字?

我想要从我的路径中排除MSG,PDFDOC使用括号使用 shell 参数扩展。

当我放在MSG括号之间时,仅删除M而不是删除MSG。我在互联网上浏览并阅读了文档,但仍然无法理解如何正确执行此操作。也许我不知道要搜索的正确关键字。

我的代码仅删除味精

find "${INPUTPATH}" -mindepth 2 -maxdepth 2 -type d -print0 | while IFS= read -r -d '' file; do
    echo "${file}"
    casenumber="${file#${INPUTPATH}/[MSG]}"
    echo "${casenumber}"
done

输入:

/home/user/output/test/PDF/2218-0
/home/user/output/test/PDF/2218-0
/home/user/output/test/DOC/2218-0
/home/user/output/test/DOC/2218-0
/home/user/output/test/MSG/2226-4
/home/user/output/test/MSG/2226-4
/home/user/output/test/MSG/2222 -2
/home/user/output/test/MSG/2222 -2
/home/user/output/test/MSG/2218-0
/home/user/output/test/MSG/2218-0

当前删除 MSG 的输出:

/home/user/output/test/PDF/2218-0
/home/user/output/test/PDF/2218-0
/home/user/output/test/DOC/2218-0
/home/user/output/test/DOC/2218-0
/home/user/output/test/MSG/2226-4
SG/2226-4
/home/user/output/test/MSG/2222 -2
SG/2222 -2
/home/user/output/test/MSG/2218-0
SG/2218-0

预期输出:

/home/user/output/test/PDF/2218-0
/home/user/output/test/PDF/2218-0
/home/user/output/test/DOC/2218-0
/home/user/output/test/DOC/2218-0
/home/user/output/test/MSG/2226-4
/2226-4
/home/user/output/test/MSG/2222 -2
/2222 -2
/home/user/output/test/MSG/2218-0
/2218-0

我其实想用这种方式删除MSG、PDF和DOC

find "${INPUTPATH}" -mindepth 2 -maxdepth 2 -type d -print0 | while IFS= read -r -d '' file; do
    echo "${file}"
    casenumber="${file#${INPUTPATH}/[MSG][PDF][DOC]/}"
    echo "${casenumber}"
done

我明白为什么上面的代码不起作用。但我首先需要解决 MSG 才能使这个工作

最终预期输出:

/home/user/output/test/PDF/2218-0
2218-0
/home/user/output/test/DOC/2218-0
2218-0
/home/user/output/test/MSG/2226-4
2226-4
/home/user/output/test/MSG/2222 -2
2222 -2
/home/user/output/test/MSG/2218-0
2218-0

答案1

[MSG]作为一个全局模式匹配任何一个字符M,SG。要匹配MSGDOCPDF,您可以使用(MSG|DOC|PDF)inzsh@(MSG|DOC|PDF)in ksh。 bash 不支持 zsh glob 运算符,但它支持 ksh 运算符的子集,包括 after shopt -s extglob,因此在 bash 中:

shopt -s extglob
casenumber=${file#"${INPUTPATH}"/@(MSG|DOC|PDF)}

将分配给,剥离与 内容匹配的最短前导部分casenumber的内容(字面上感谢它周围的引号,与 zsh 相反,ksh/bash 中需要这些引号),然后是,或。$file$INPUTPATH/MSGDOCPDF

在 ksh 中,只需省略shopt -s extglobbash 特定且 ksh 中不需要的 。在 zsh 中:

casenumber=${file#$INPUTPATH/(MSG|DOC|PDF)}

答案2

实际上并不是通配符,但是......

=~当在扩展测试括号中使用时,Bash 的最新版本可以使用其 RegEx 运算符进行基于正则表达式的匹配[[ ... ]]...它可以执行捕获组(...)并具有一个内置BASH_REMATCH数组,其中第零个索引${BASH_REMATCH[0]}指整个匹配,下一个索引${BASH_REMATCH[1]}指第一个捕获组匹配,下一个${BASH_REMATCH[2]}指第二个捕获组匹配,依此类推。

所以,你可能会做这样的事情:

$ printf '%s\0' "/home/user/output/test/PDF/2218-0" "/home/user/output/test/DOC/2218-0" "/home/user/output/test/MSG/2226-4" |
while IFS= read -r -d '' file; do
  [[ "$file" =~ .*(DOC|MSG|PDF)(.*) ]] && printf '%s\n' "$file" "${BASH_REMATCH[2]}"
  done
/home/user/output/test/PDF/2218-0
/2218-0
/home/user/output/test/DOC/2218-0
/2218-0
/home/user/output/test/MSG/2226-4
/2226-4

答案3

不是回答你的确切问题,而是关于这个特殊案例的一些注释。

鉴于您在find "${INPUTPATH}" -mindepth 2 -maxdepth 2那里,所有生成的路径在初始路径之后应该只有一个斜杠$INPUTPATH,因此您可以忽略那里有哪个特定的三字母字符串,而只删除下一个之前的任何内容/

casenumber=${file#"${INPUTPATH}"/*/}

或者,因为它是最后一个斜杠,所以只需删除一切直到最后/

casenumber="${file##*/}"

在这里,加倍#意味着采取最长的比赛。

另外,如果您先在运行之前,您可以$INPUTPATH从输出中删除该部分(仅将其替换为 ) :.cdfind

(cd -P -- "${INPUTPATH}" && find . -mindepth 2 -maxdepth 2 -type d -print0) |
 while IFS= read -r -d '' file; do
    echo "${file}"
    casenumber="${file#./*/}"
    echo "${casenumber}"
done

相关内容