BASH:如何在 sed 命令中对字符串使用 Regex Negative Lookahead?
Posted
技术标签:
【中文标题】BASH:如何在 sed 命令中对字符串使用 Regex Negative Lookahead?【英文标题】:BASH: How to use Regex Negative Lookahead in sed command for a string? 【发布时间】:2019-06-01 17:03:01 【问题描述】:我还没有找到一种方法在 sed 命令中使用这个正则表达式 - .+?(?=,) 来提取这个字符串的一部分(使用第一个字符实例的 Lookbehind)。
用简单的英语,我想提取位于第一个逗号之前的字符串部分。由于我计划将来提取字符串的特定文件名,因此我不能依赖 cut 命令(我最终将不得不使用 sed 命令),:-
name='ERROR 1: /home/rphillips/Desktop/empties/BN23_2303.tif, band 1: 无法计算统计数据,采样中找不到有效像素。'
这些是我使用过的变体,包括一个有效的测试 - sed 's/band/rose/'。然而,我使用的其他变体(如下所示)将空格作为输出。
while read -r line; do
name="$line"
echo $name
#file_path=$(echo $name | cut -d "," -f 1)
#file_path=$(echo $name | sed -e '/s\/.+?(?=,)///')
#file_path=$(echo $name | sed 's/band/rose/')
file_path=$(echo $name | sed '/s\/.+?(?=, )///')
#file_path=$(echo $name | grep -P '.+?(?=,)')
#file_path=$(echo $name | sed
#file_path=$(echo $name | awk '/.+?(?=,)/print $name'
echo $file_path
done < "$filename"
预期结果 - 错误 1:/home/rphillips/Desktop/empties/BN25_2303.tif
实际结果 - '很多空间'
我还注意到,根据 Regex101 网站,我使用的正则表达式具有不同的“匹配”,具体取决于我是在 Windows 上使用 Firefox 还是 Ubuntu 16.04LTS
Windows - https://regex101.com/r/WWGf8F/1 Ubuntu - https://regex101.com/r/NpL2Oa/1
我不确定这是否导致 sed -e
无法识别表达式?
我已经将这些引用用于上面代码中使用的不同表达式
https://likegeeks.com/regex-tutorial-linux/
How to match "anything up until this sequence of characters" in a regular expression?
https://www.regular-expressions.info/lookaround.html?wlr=1
https://linux.die.net/man/1/sed
【问题讨论】:
sed 's/,.*//'
将带来所需的输出,尽管我不确定这是否是您想要做的。你会用 English 指定你想要执行的过程吗,因为你的命令sed '/s\/.+?(?=, )///'
不起作用并且不清楚你想要做什么。请注意,我不是反对者。
同意,sed 's/,.*$//'
或 sed 's/^\([^,][^,]*\).*$/\1/'
。要么做你想做的事。 (或grep -o '^[^,]*'
或awk -F, 'print $1'
)
sed
仅保证支持 BRE(“POSIX 基本正则表达式”),并且许多版本还提供了访问 ERE 语法的扩展。 Lookahead 和lookbehind 是PCRE 扩展,不是任何一个标准的一部分。见pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
顺便说一句,echo $name
本质上是错误的——参见BashPitfalls #14。按优先顺序使用<<<"$name"
、printf '%s\n' "$name"
或echo "$name"
带引号。
...你不需要sed
来做一些简单的事情,比如在字符串中修剪逗号后面的所有内容。如果string=foo,bar
,则$string%%,*
将评估为foo
。
【参考方案1】:
用简单的英语我想提取字符串中存在的部分 在第一个逗号之前。因为我计划在未来提取 字符串的特定文件名,我不能依赖 cut 命令(我 最终将不得不使用
sed
命令)
输入字符串
ERROR 1: /home/rphillips/Desktop/empties/BN23_2303.tif, band 1: Failed to compute statistics, no valid pixels found in sampling.
预期结果
ERROR 1: /home/rphillips/Desktop/empties/BN25_2303.tif
在我们了解您的sed
命令不起作用的可能原因之前,让我们看看您上面的实际问题。如果您只是想提取第一个逗号之前的文本,那么您只需要:
sed 's/,.*//'
(简单地说删除从第一个逗号到结尾的所有内容)
您也可以使用反向引用(这将有助于实现提取文件名的最终目标),例如
sed 's/^\([^,][^,]*\).*$/\1/'
(表示'^'
从开头开始,\([^,][^,]*\)
捕获至少 1 个非逗号字符的所有文本,包括零个或多个非逗号字符,.*$
丢弃所有文本到结尾和\1
仅使用反向引用替换捕获的文本)
要达到仅提取文件名的目标,您只需修改上述内容以使用第一个正斜杠开始捕获,例如
sed 's/^[^/]*\([^,][^,]*\).*$/\1/'
使用/输出示例
$ sed 's/^[^/]*\([^,][^,]*\).*$/\1/' <<< $name
/home/rphillips/Desktop/empties/BN23_2303.tif
我不确定这是否会导致表达式无法被
sed -e
?
sed
没有-E
(--regexp-extended
) 选项使用基本 正则表达式(不包括向后或向前)。
如果您打算使用逗号分隔值的剩余字段,您可能需要考虑使用awk
来解析这些字段。您可以轻松获取所有指定 -F
字段分隔符的字段和一个简单的循环。
$ awk -F', ' 'for (i = 1; i <= NF; i++) printf "field %d - %s\n", i, $i' <<< $name
field 1 - ERROR 1: /home/rphillips/Desktop/empties/BN23_2303.tif
field 2 - band 1: Failed to compute statistics
field 3 - no valid pixels found in sampling.
(您也可以在循环中使用条件进一步解析每个字段)
在 Bash 中 - 只需要参数扩展
不要只见树木不见森林,因为您指定了bash
,如果您只是想从name
中提取文件名,您所需要的只是带有子字符串删除的参数扩展 (先从右,再从左),例如
tmp=$name%%,* ## trim to (and including) the 1st comma from the right
echo "/$tmp#*/" ## trim to and including the first / from the left
/home/rphillips/Desktop/empties/BN23_2303.tif
(一种更有效的方法)
查看一下,如果您还有其他问题,请告诉我。
【讨论】:
以上是关于BASH:如何在 sed 命令中对字符串使用 Regex Negative Lookahead?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 BASH 中的 sed 命令从 Json 文件中删除 Json 对象
如何在bash脚本中使用Bash / Sed / Awk / Perl删除分隔字符串的最后一个元素[duplicate]