使用内置函数来增强性能是否会因无偿使用子外壳而被否定?
Is using builtins to enhance performance negated by gratuitous use of subshells?
我正在编写一个脚本,我需要在其中确保字符串包含逗号。如果没有,我需要脚本退出。考虑以下内容,我的意图是仅使用内置函数来提高性能:
#!/bin/sh
check_for_commas='This string must contain a comma'
comma_found='0'
iterate_through_string="$check_for_commas"
while [ -n "$iterate_through_string" ]; do
char="$(printf '%.1s' "$iterate_through_string")"
if [ "$char" = ',' ]; then
comma_found='1'
break
fi
iterate_through_string="${iterate_through_string#?}"
done
if [ "$comma_found" != '1' ]; then
echo 'Your string does not contain a comma. Exiting...'
exit
else
echo 'Found a comma in the string. Script can continue...'
fi
我在这个脚本中使用命令替换,它为它迭代的每个字符生成一个子 shell。与此比较:
#!/bin/sh
check_for_commas='This string must contain a comma'
if [ "$(echo "$check_for_commas" | grep -q -F ','; echo "$?")" = '1' ]; then
echo 'Your string does not contain a comma. Exiting...'
exit
else
echo 'Found a comma in the string. Script can continue...'
fi
我显然不介意做一些额外的工作来获得额外的性能。但我担心使用这么多子外壳已经违背了我的全部初衷。
当无偿使用 subshell 出现时,我对仅使用内置函数来提高性能的追求是否变得毫无用处?
命令替换,如 $(printf ...)
中的那样,确实很昂贵 -- 并且您在这里所做的事情不需要它们。
case $check_for_commas in
*,*) echo "Found a comma in the string";;
*) echo "No commas present; exiting"; exit 1;;
esac
在更一般的情况下——单独的 fork()
成本低于一对 fork()/execve()
,因此拥有一个子 shell 比单个 external-command 调用更便宜;但是如果你比较一个生成多个子 shell 的循环与一个 external-command 调用,哪个更便宜取决于你的循环将迭代多少次(以及这些东西在你的操作系统上的成本是多少——forks 是例如,在 Windows 上传统上非常昂贵),因此是一项 fact-intensive 调查。 :)
(谈到最初提出的代码——请注意,ksh93 将在特定的 var=$(printf ...)
情况下优化掉 fork
;相比之下,在 bash 中,您需要使用printf -v var ...
得到相同的效果)。
这是一个简短的 POSIX shell 函数,它使用组合的 删除匹配前缀模式 和 删除匹配的后缀模式,和test
,(或者更确切地说[
是一回事),到return a true 标记是否有逗号:
chkcomma(){ [ "${1#${1%,*}}" ] ; }
没有逗号的例子:
chkcomma foo && echo comma found || echo no comma
输出:
no comma
逗号示例:
chkcomma foo,bar && echo comma found || echo no comma
输出:
comma found
这可以进一步抽象为使用 globbing:
查找子字符串
# Usage: instr globpattern string
# returns true if found, false if not.
instr(){ [ "${2#${2%*}}" ] ; }
示例:
instr '[Mm]oo' mood && echo found
输出:
found
我正在编写一个脚本,我需要在其中确保字符串包含逗号。如果没有,我需要脚本退出。考虑以下内容,我的意图是仅使用内置函数来提高性能:
#!/bin/sh
check_for_commas='This string must contain a comma'
comma_found='0'
iterate_through_string="$check_for_commas"
while [ -n "$iterate_through_string" ]; do
char="$(printf '%.1s' "$iterate_through_string")"
if [ "$char" = ',' ]; then
comma_found='1'
break
fi
iterate_through_string="${iterate_through_string#?}"
done
if [ "$comma_found" != '1' ]; then
echo 'Your string does not contain a comma. Exiting...'
exit
else
echo 'Found a comma in the string. Script can continue...'
fi
我在这个脚本中使用命令替换,它为它迭代的每个字符生成一个子 shell。与此比较:
#!/bin/sh
check_for_commas='This string must contain a comma'
if [ "$(echo "$check_for_commas" | grep -q -F ','; echo "$?")" = '1' ]; then
echo 'Your string does not contain a comma. Exiting...'
exit
else
echo 'Found a comma in the string. Script can continue...'
fi
我显然不介意做一些额外的工作来获得额外的性能。但我担心使用这么多子外壳已经违背了我的全部初衷。
当无偿使用 subshell 出现时,我对仅使用内置函数来提高性能的追求是否变得毫无用处?
命令替换,如 $(printf ...)
中的那样,确实很昂贵 -- 并且您在这里所做的事情不需要它们。
case $check_for_commas in
*,*) echo "Found a comma in the string";;
*) echo "No commas present; exiting"; exit 1;;
esac
在更一般的情况下——单独的 fork()
成本低于一对 fork()/execve()
,因此拥有一个子 shell 比单个 external-command 调用更便宜;但是如果你比较一个生成多个子 shell 的循环与一个 external-command 调用,哪个更便宜取决于你的循环将迭代多少次(以及这些东西在你的操作系统上的成本是多少——forks 是例如,在 Windows 上传统上非常昂贵),因此是一项 fact-intensive 调查。 :)
(谈到最初提出的代码——请注意,ksh93 将在特定的 var=$(printf ...)
情况下优化掉 fork
;相比之下,在 bash 中,您需要使用printf -v var ...
得到相同的效果)。
这是一个简短的 POSIX shell 函数,它使用组合的 删除匹配前缀模式 和 删除匹配的后缀模式,和test
,(或者更确切地说[
是一回事),到return a true 标记是否有逗号:
chkcomma(){ [ "${1#${1%,*}}" ] ; }
没有逗号的例子:
chkcomma foo && echo comma found || echo no comma
输出:
no comma
逗号示例:
chkcomma foo,bar && echo comma found || echo no comma
输出:
comma found
这可以进一步抽象为使用 globbing:
查找子字符串# Usage: instr globpattern string
# returns true if found, false if not.
instr(){ [ "${2#${2%*}}" ] ; }
示例:
instr '[Mm]oo' mood && echo found
输出:
found