您好,我有一个包含以下字符串的 md 文件,我想为此编写一个正则表达式。
状况
- id 可以是任何东西。
- 类型为 youtube、vimeo 等
- ID 和类型为必填字段
{% include video.html id="T3q6QcCQZQg" type="youtube" %}
所以我想检查 bash 脚本中的字符串格式是否正确,否则会出现错误。
当前的代码如下所示。下面的代码可以在没有 ID 的情况下为我工作。但我还需要为 id 添加正则表达式
IFS=$'\n' read -r -d '' -a VIDEOS < <( grep "video.html" "$ROOT_DIR$file" && printf '\0' )
#output => {% include video.html id="T3q6QcCQZQg" type="youtube" %}
for str in "${VIDEOS[@]}"
do
if [[ "$str" =~ ({%)[[:space:]](include)[[:space:]](video.html)[[:space:]](type="youtube"|type="vimeo")[[:space:]](%})$ ]]; then
flag="dummy"
echo "Invalid format:: $second"
fi
done
请帮忙
答案1
原则上你已经差不多了。以下是基于您提供的示例内容的正则表达式的最小可测试版本:
#!/bin/bash
VIDEOS=( '{% include video.html id="T3q6QcCQZQg" type="youtube" %}' '{% include video.html id="330853122" type="vimeo" %}' '{% include video.html id="330853122" type="nosuchplatform" %}')
regex='^\{% include video.html id="[^"]+" type="(youtube|vimeo)" %\}$'
for v in "${VIDEOS[@]}"
do
if [[ "$v" =~ $regex ]]
then
echo "$v : valid"
else
echo "$v : invalid"
fi
done
id
可以使用以下结构来匹配变化的字段"[^"]+"
,即“一个开始"
,后跟任何不是a "
,然后是一个"
"。如果您知道该字段允许使用哪些字符id
,则可以使其更具体,即如果您知道它只能是字母数字字符,请尝试"[[:alnum:]]+"
改为。
通过将正则表达式存储在 shell 变量中,您可以避免在制定正则表达式时遇到的一些问题,只需确保不是在测试中使用变量时引用该变量。
我还假设,如果正则表达式与您想要输出的匹配valid
(目前您会将=~
测试的成功视为“无效”模式)。
答案2
由于id
和type
标签(可能)不需要按这个顺序,我会使用一系列正则表达式测试:
for str in "${VIDEOS[@]}"; do
if [[ $str =~ \{%[[:blank:]]+include[[:blank:]]+.*[[:blank:]]+%\} ]] &&
[[ $str =~ \<id=\"[^\"]+\" ]] &&
[[ $str =~ \<type=\"(youtube|vimeo)\" ]]
then
echo "valid"
else
echo "invalid"
fi
done
答案3
bash
非常擅长协调其他程序的执行,但它对于文本处理来说是一种糟糕的语言。为此,您应该使用awk
or 。perl
看为什么使用 shell 循环处理文本被认为是不好的做法?。
例如,使用 perl“one-liner”:
$ perl -lne 'next unless m/{%.*video\.html.*%}/;
($id) = m/\bid\s*=\s*"([^"]+)"/i;
($type) = m/\btype\s*=\s*"(youtube|vimeo)"/i;
print "Invalid format on line $. of $ARGV: $_" unless ($id && $type);' *.md
这允许id
和type
可以在行中的任何位置采用任何顺序,并且还允许在符号\s*
周围有可选的额外空格 ( ) =
。它期望整个视频包含在一行上(更强大的版本可以允许多行字符串,但此脚本不会这样做)。它可以一次处理多个输入文件(例如*.md
),并会告诉您它找到的任何无效行的行号和文件名。
如果您想允许任何值$type
(不仅仅是 youtube 或 vimeo),请将第三行替换为:
($type) = m/\btype\s*=\s*"([^"]+)"/i;
或者只是在交替中添加更多允许的类型。
与独立可执行文件相同的脚本:
#!/usr/bin/perl
use strict;
while(<>) {
chomp;
next unless m/{%.*video\.html.*%}/;
my ($id) = m/\bid\s*=\s*"([^"]+)"/i;
#my ($type) = m/\btype\s*=\s*"([^"]+)"/i;
my ($type) = m/\btype\s*=\s*"(youtube|vimeo)"/i;
print "Invalid format on line $. of $ARGV: $_\n" unless ($id && $type);
}
例如另存为verify-videos.pl
PATH 中的某个位置(例如~/bin/
或/usr/local/bin/
)并使用chmod +x /path/to/verify-videos.pl
.