我有一个“命令”文本文件,它在每一行发出数据文件下载命令。我将命令文件发送到 bash。但是,一小部分下载会失败。这是我用来找出缺失内容的算法:
- 下载后,我返回命令文件并检查每个下载文件是否存在。
- 如果下载不存在,我会将命令行复制到新的命令文件中。
- 我留下了一个新的命令文件用于剩余的下载。
这是我实现该算法的 bash 脚本:
1 #!/bin/bash
2 while read line
3 do
4 for item in $line
5 do
6 if [[ $item == *out_fname* ]]; then
7 splitline=(${item//=/ })
8 target_file=${splitline[1]}
9 if [ ! -f $target_file ]; then
10 echo $line >> stillneed.txt
11 fi
12 fi
13 done
14 done < "$@"
问题:这很好用,但是有没有更好的算法或实现(也许使用 bash 以外的东西)?我所做的只是让 bash 做人类必须做的事情。但 Unix 似乎总是有更好的做事方式......
答案1
看来您正在寻找“out_fname=”,而不仅仅是“out_fname”。
我要么混合使用 awk 和 shell,要么使用 python。在 awk/shell 中:
awk '{for(i=0;i<NF;i++) {if (index($i, 'out_fname=')) {split($i,A,/=/);print A[i]}}' "$@" |
while read filename; do
if [ ! -f $filename ]; then echo $filename; fi
done > stillneed.txt
在Python中:
import fileinput, os
stillneed = open("stillneed.txt", "w")
for line in fileinput.input():
for filename in [l.split('=')[1] for l in line.split() if l.find('out_fname=')!=-1]:
if not os.path.exists(filename):
print >>stillneed, filename
答案2
不确定它是否有帮助,但我有一个函数可以重试命令,直到它们返回成功:
retry () {
local delay=1 n
if ! [[ $1 = *[^0-9]* ]]; then
# TODO allow delay=0 (prevents Ctrl-C)
if (($1 > 0)); then
delay=${1:1}
fi
shift
fi
# run command
while ! "$@"; do
echo "retrying in ${delay}s"
for ((n=delay; n>0; n--)); do
sleep 1 || return
done
done
}; export -f retry
答案3
不要在初始下载脚本完成后检查缺少的内容,而是考虑向所述下载脚本添加一些检查。我没有测试以下内容,我只是把它写在我的脑海中:
cat files_to_download|while read file;
do
SUCCESS="False"
while [[ $SUCCESS == "False" ]];
do
wget $file;
if [[ $? -eq 0 ]];
then
SUCCESS="True"
fi
done
done
答案4
我建议echo
在下载失败时复制该行,而不是随后通过解析文件中的每一行来检查文件名:
[[ -f $1 ]] || { echo "$1 not found" >&2; exit 1; }
while read -r line; do
$line || echo "$line" >> stillneed
done < "$1"
这会更有效,也意味着您将来无需担心任何奇怪的文件名(例如,其中有空格)。
如果您想改进现有方法,可以使用标准参数扩展:
for f; do
while read -r line; do
for item in $line; do
[[ $item = out_fname=* ]] || continue
[[ -f ${item#out_fname=} ]] || echo "$line"
break # assuming one fname per line
done
done < "$f"
done > stillneed
..但考虑一下会发生什么:out_fname='foo bar.ext'
.另外,请记住,这会在事件发生后检查每一行,而我们可以在运行该命令时检查该命令是否有效。
stillneed
整个循环打开一次,效率更高;我没有在第一个代码片段中这样做,因为我们很可能希望看到下载命令的输出。这里只有测试,没有运行外部命令,因此打开文件一次是有意义的。 (请注意,使用>
将在开始时截断文件;我曾经for f
允许多个输入文件作为位置参数:如果需要,添加上面相同的内容应该很容易。)
我必须强调的一件事是 quoting:echo "$line"
与echo $line
.一般来说,报价全部参数扩展(这包括变量),除非您确定要进行字段分割。