Bash的这条神奇路线我无法理解,有人能解释一下它是什么吗';他在干什么?
我在这条线上找到了它: 我试图在代码中使用它: 这是我不明白的部分,特别是第三行Bash的这条神奇路线我无法理解,有人能解释一下它是什么吗';他在干什么?,bash,sed,grep,Bash,Sed,Grep,我在这条线上找到了它: 我试图在代码中使用它: 这是我不明白的部分,特别是第三行 [ $# = 0 ] && help while [ $# -gt 0 ]; do CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g") if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not suppor
[ $# = 0 ] && help
while [ $# -gt 0 ]; do
CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g")
if [ -z "$CMD" ]; then echo "ERROR: Command '$1' not supported"; exit 1; fi
shift; eval "$CMD" $@ || shift $? 2> /dev/null
谢谢你的帮助 bash(1)
并不是那么“神奇”,尽管它确实让用户感觉自己像个巫师!破译它的关键是知道要查看哪些手册页。或者,如果你是一个语言人(像我一样),认识到bash是一种小小的粘合语言;其他一些小语言以小工具的形式散布在它上面,比如grep(1)
,sed(1)
,awk(1)
,cut(1)
,等等
那么,让我们深入探讨一下:
[ $# = 0 ] && help
这就是说,运行[
测试命令;如果成功,则运行help命令。$#
是参数数。在shell上运行帮助测试
,以了解其工作原理(帮助
仅适用于需要的其他内置代码man(1)
)
while循环的开始。注意:大多数现代bash程序员会使用[[$\35;>0]]
(除非他们需要兼容POSIX sh)或(($\35;>0))
在parens中运行这些东西,并将输出存储在CMD中(bash的手册阐明了这是如何工作的)
在go.sh
中搜索特定模式(有关正则表达式的详细信息,请参见man re_format
,有关选项的作用,请参见man grep
。例如,-o
表示只打印匹配项,而不是整行)
将grep的结果作为sed的输入输出。mansed
对于它的小语言来说是一个很好的资源。s/-/\ug
将所有-
替换为
;更惯用的方法是使用tr而不是sed:tr-
if [ -z ... ]
测试参数是否为空。if的其余部分记录消息并退出
shift
从$@
中弹出一个命令行参数,因此现在少了一个
eval "$CMD" "$@"
使用剩余的参数运行CMD字符串(最好在这里使用数组)
|| shift $? 2>/dev/null
如果失败,则将尽可能多的参数转换为退出代码($?
),并将错误消息重定向到/dev/null
(例如,当没有足够的参数进行转换时)
这一部分有点奇怪,可能只有在应用程序的上下文中才有意义。通常,退出代码不会告诉您要转换什么。但是您可以这样编程
CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g")
上面的行是从文件go.sh
中最大映射1行(-m1),仅匹配正则表达式(-Po
):
“^##*$1,--\K[^=]*.-\K${1#--}(?:[=])”
($1
被while循环中当前正在处理的脚本参数替换)
然后grep命令的结果通过管道传输到
sed
,其中每个'-'都被更改为'.':sed-e“s/-/\ug”
。这个操作的结果字符串成为CMD变量的值。另一个答案解释了脚本的其余部分,我将尝试解释grep
grep
-仅打印第一个匹配项-m1
-使用perl正则表达式-P
-仅打印匹配的字符串-o
“^##*$1,--\K[^=]*.-\K${1}(?:[=])”
或两个正则表达式。因此,我们搜索一个正则表达式或另一个正则表达式|
“重置行位置”。基本上这意味着使用\K
它将把-o
的结果打印到与正则表达式匹配的末尾。它通常一起使用\K
grep-Po'blablablabla\Kblabla'。例如
echo abcde | grep-P'ab\K..
将打印
de`
^##*$1,--\K[^=]*
- 搜索一行
。然后打印出零件##,-->
。因此,从
到下一个空格或-->
打印出来=
- 搜索一行
^##.*-\K${1#--}(?:[=])
是perl中“不使用内存”的分组。(?:…)
与(?:某物)
相同(某物)
- 搜索转到
##--
- 因此,基本上grep希望找到类似
或##first_arg,-
的内容,其中##blabla--
是脚本中当前的第一个参数,它将输出first_arg
中的部分
sed
-只需将所有“s/-/\ug/g”
替换为-
grep-P
和\K
以及lookaheads。天哪,你太棒了!多亏了你的智慧,我现在正在重写整个部分,它将变得干净易读!@moop谢谢!我做了很多bash编程;有(与某些信念相反)最佳实践(特别是可读性和错误处理)。我的一些脚本在GitHub上,应该链接到我的个人资料中。另外,请参阅,这是,我的脚本达到了任何质量标准吗?小心ABS,它是一个混合包。你发现什么让人困惑?它给CMD赋值。它给的值是一个写得不好的grep的输出,它通过管道传输到sed,应该使用tr
,这应该告诉您应该避免使用代码,而不是模拟代码。这里唯一可能让人困惑的是regex,它绝对应该简化。也许${1#--}
也让您困惑。我不会模拟此代码。避免使用它。eval“$CMD”$@| | shift$?
应该会让你尖叫着跑。@williampersell我觉得很困惑。这解决了正则表达式问题!我从调试器及其
shift
eval "$CMD" "$@"
|| shift $? 2>/dev/null
CMD=$(grep -m 1 -Po "^## *$1, --\K[^= ]*|^##.* --\K${1#--}(?:[= ])" go.sh | sed -e "s/-/_/g")