输入将是如下文件名:
A-B-000001-C
A-B-000002-C
.....
.....
A-B-999999-C
所有文件应该是连续的。我想找到丢失的连续文件名。为此,我使用分隔 6 位序列号awk 并使用grep使用正则表达式检查文件是否存在于目录中。
`ls|grep "A-B-${sequencenumber}-.*"|wc -l`
但 shell 脚本不会将数字视为十进制,并且如果我使用以下命令强制将数字视为十进制10#$序列号然后删除搜索文件所需的前面的零。
有没有办法解决?
答案1
某些 shell(例如 bash)在其算术表达式中将带有前导零的数字视为八进制。解决这个问题的一个技巧是仅操作带有额外非零前导数字的数字,例如从 1000001 到 1999999 的计数。要获得带有前导零的所需数字,请使用字符串操作去除前导 1。
n=1000001
while [ "$n" -le 1999999 ]; do
digits=${n#1}
set "A-B-$digits-."*
if [ -e "$1" ] || [ -L "$1" ]; then
echo "${digits}: $#"
fi
n=$((n+1))
done
此方法可移植到所有 POSIX shell,并避免为计算创建子进程,这可以使其更快(但无论如何,一百万次迭代可能会很慢,shell 的性能并不是最好的)。
在上面的脚本中,我没有使用涉及ls
和wc
来计算匹配文件的复杂而缓慢的命令,而是使用 shell 内置结构:set "A-B-$digits-."*
将位置参数设置为匹配文件列表,下面的行打印匹配数 ( $#
) if至少有一个匹配项(如果没有匹配项,则模式保持不变,因此[ -e "$1" ]
为[ -e "A-B-$digits-.*" ]
false)。
答案2
答案3
wc -l
如果文件名包含换行符,使用将不会产生正确的结果。
通过bash
and zsh
,您可以使用大括号扩展:
for n in {000001..999999}; do
f=A-B-$n-C
[ -f "$f" ] || printf '%s missing\n' "$f"
done
ksh93
带有braceexpand
选项启用:
for n in {1..999999%06d}; do
: the code above
done
在ksh
和中zsh
,您可以执行以下操作:
typeset -Z6 i=1
max=999999
while [ "$i" -le "$max" ]; do
f=A-B-$i-C
[ -f "$f" ] || printf '%s missing\n' "$f"
: "$((i+=1))"
done
POSIXly:
min=1
max=999999
while [ "$min" -le "$max" ]; do
f=$(printf "A-B-%0${#max}d-C" "$min")
[ -f "$f" ] || printf '%s missing\n' "$f"
: "$((min+=1))"
done
答案4
awk
为我工作:
set x=`echo $< | awk '{printf "%d",$1}' ` ; echo $x
033 # this is what I entered
33 # this prints out