我有一个包含前导零数字的变量,我想 grep 这个变量和同一个变量加一。我做了几次尝试,但遇到了错误。这就是我想做的:
read var
newvar=$(($var +1))
grep '$var' /some/dir
grep '$newvar' /some/dir
我真的认为我的代码有问题。我也尝试过一些这样的测试:
#!/bin/bash
echo "enter number"
read number
newnumber=$(($number + 1))
echo "$newnumber"
这给了我一个错误:value too great for base (error token is
。如果我这样做:
#!/bin/bash
echo "enter number"
read number
number=""
newnumber=$(($number + 1))
echo "$newnumber"
这将始终输出 1。
我的尝试出了什么问题,我该如何做我想做的事?
答案1
您使用了错误的引号:单引号会阻止表达式''
的扩展( and以及旧形式)。请改用双引号。尽管在这种情况下,如果您确定它是一个数字,那么您不需要$
$var
$(command)
`command`
""
任何引号。
对于你的第二个问题......你使用前导零吗?这表示八进制,因此数字8
和9
不起作用。
答案2
极客龙已经解释了为什么你的第一次尝试失败了。以下是有关您尝试执行的操作的一些其他提示。
如果您正在寻找类似 的数字42
,您可能想要匹配042
,但不想匹配1042
或421
。要实现这一目标,您所需要的只是一个更高级的正则表达式。假设$newnumber
包含没有前导零的数字(整数、正数、十进制表示形式),则查找$newnumber
前面是行首或非数字字符的字符,后面同样如此。0*
进一步允许前导零。该-E
选项表明grep
您正在使用现代正则表达式语法(而不是历史语法,后者更奇怪且功能更弱)。
grep -E "(^|[^0-9])0*$newnumber(\$|^[0-9])" /path/to/file
要在 bash 中解析带有潜在前导零的数字,您可以使用$((10#$newnumber))
强制进行十进制解释。在其他 shell 中,情况稍微复杂一些;有一个 shell 构造可以获取没有特定前缀的变量的值${var#prefix}
,还有一个类似的后缀构造${var%suffix}
,但是没有办法指定“最长的可能0
字符序列”作为要 strip 的前缀。但它可以分两步完成:首先获取var
不是前导零的部分,并将其用作剥离的前缀。不是前导零的部分var
是其以非零开头的最长后缀,即${var%%[!0]*}
(双精度%
表示取出与模式匹配的最长后缀;单精度%
表示取出最短的后缀)。
read number
number=${number#${number%%[!0]*}}
进一步说明:grep REGEXP /some/file
搜索单个文件/some/file
。如果要搜索目录中的所有文件,请让 shell 生成文件列表:grep REGEXP /some/dir/*
.如果要递归搜索目录及其子目录中的所有文件,请将选项传递-r
给以grep
使其递归:grep -r REGEXP /some/dir
。
答案3
正如 geekosaur 所说,您使用了错误的引号。当您希望 shell 将变量引用扩展为值时,请坚持使用双引号。
其次,你在双括号内的数学运算是错误的。您不希望其中有 $,$(( )) 构造内的变量引用不需要 $。
#!/bin/bash
echo "enter number"
read number
newnumber=${number#${number%%[!0]*}}
newnumber=$((newnumber + 1))
echo "$number changes to $newnumber"
这两个更改在你的原版中也对我有用......
read var
newvar=${var#${var%%[!0]*}}
newvar=$((newvar + 1))
printf -v newvar "%02d" "$newvar"
grep "$newvar" /some/dir
更新添加了printf
格式化输出的行。
更新2添加了用于输入零填充数字的修复。现在这应该是一个完整的例子了。
答案4
一堆部分答案:
如何处理带有前导零的数字 v1:
newvar=$(printf '%s + 1\n' "$var" | bc)
或者,等价地,
newvar=$(bc <<< "$var + 1")
因为bc
不将带有前导零的数字视为八进制。
据我所知,这不会造成代码注入漏洞,因为bc
似乎没有 shell 转义功能。 (我可能忽略了一些东西。)请注意,这个问题并没有说“仅 bash”。
如何处理带有前导零的数字 v2:
newvar=$((1$var - 10000 + 1))
显然,这使用了一个技巧,姚莉想做的事: 通过1
前置0042
作为字符串操作,
您将得到 string 10042
,该字符串被处理为十进制数。请注意,在此构造中,您必须包含 $
in$var
以使 the1
和 the $var
被解析为两个单独的单元(然后连接)。
如果已知输入值的长度为四位数字(例如 0042
),请按原样使用上述命令。如果它们有其他长度(提前已知),请将10000
上面的 更改为1
后跟适当数量的零。
如果你不提前知道长度,做
pow10="1$(printf "%0${#var}d" 0)"
或者
pow10="1$(printf '%0*d' "${#var}" 0)"
如果数字是四位数字长(例如, 0042
),这些基本上用于printf '%04d' 0
生成0000
,然后在前面加上 a 1
以获得 10000
。然后做
newvar=$((1$var - pow10 + 1))
如何向newvar
结果添加前导零:
马克的回答表明您可以使用
printf -v newvar '%04d' "$newvar"
或者,等价地,
newvar=$(printf '%04d' "$newvar")
添加足够的前导零,使其$newvar
总数达到四位数。如果您事先不知道长度,可以使用上一节中的技术:
newvar="$(printf "%0${#var}d" "$newvar")"
或者
newvar="$(printf '%0*d' "${#var}" "$newvar")"