想知道我是否可以帮忙解析命令的输出duplicity collection-status MYPATH
我的最终目标是构建一个“恢复”脚本,该脚本将使用此命令并构建一个可选择的备份列表以供恢复。
现在,我的代码如下:
# get the backups information
_t=`duplicity collection-status $1`
# split the collection based on new lines
IFS=$'\n' _arr=($_t)
# find the length of the array
_arr_len=${#_arr[@]}
# we only want the last set of lines, minus the last 2 lines
_end=`expr $_arr_len - 2`
# loop over our resulting set and echo out the line
_idx=1
_menu_idx=1
_ret_arr=()
# make sure there are actually backups created
if [[ -z ${_arr[14]} ]]; then
# it doesnt exist, show a message and exit
echo
echo '--------------------------------------------------------------------';
echo 'There are no backups for that account/app'
echo 'Please create the account, and make sure it matches the restore'
echo 'Account and App names'
echo '--------------------------------------------------------------------';
echo
exit 1;
fi;
echo
echo '--------------------------------------------------------------------';
echo "- Select a restore point: "
for _l in ${_arr[@]}; do
if [ $_idx -ge 14 -a $_idx -le $_end ]; then
IFS=$' ' _temp_arr=($_l)
_d_string=${_temp_arr[1]}" "${_temp_arr[2]}" "${_temp_arr[3]}" "${_temp_arr[4]}" "${_temp_arr[5]}
_ret_arr+=( "$_d_string" )
# Tue Aug 27 10:59:43 2019
echo $_menu_idx") "$_d_string;
((_menu_idx=_menu_idx+1))
fi;
((_idx=_idx+1))
done
read n
# get the value of the selected item
_t=${_ret_arr[$n-1]};
# make sure the selection is valid
if [[ -z $_t ]]; then
echo "You selected an invalid restore point. Please try again"
exit 1;
fi;
echo
# convert the selected value to a epoch date and return it
_ret_date=$(date -d "${_t}" +"%s");
虽然这似乎满足了我的目的,但我在几台不同的服务器上发现,我在前后都得到了一些“额外”的文本,因此列表并不总是备份点。示例输出的结构有点像这样:
root@sp-stage1:~# duplicity collection-status $_dest/$_host/apps/aats/aats/
Synchronizing remote metadata to local cache...
Copying duplicity-full-signatures.20190903T134927Z.sigtar.gz to local cache.
Copying duplicity-full.20190903T134927Z.manifest to local cache.
Copying duplicity-inc.20190903T134927Z.to.20190903T162118Z.manifest to local cache.
Copying duplicity-inc.20190903T162118Z.to.20190904T050005Z.manifest to local cache.
Copying duplicity-inc.20190904T050005Z.to.20190905T050004Z.manifest to local cache.
Copying duplicity-inc.20190905T050004Z.to.20190906T050005Z.manifest to local cache.
Copying duplicity-inc.20190906T050005Z.to.20190907T050005Z.manifest to local cache.
Copying duplicity-inc.20190907T050005Z.to.20190908T050004Z.manifest to local cache.
Copying duplicity-new-signatures.20190903T134927Z.to.20190903T162118Z.sigtar.gz to local cache.
Copying duplicity-new-signatures.20190903T162118Z.to.20190904T050005Z.sigtar.gz to local cache.
Copying duplicity-new-signatures.20190904T050005Z.to.20190905T050004Z.sigtar.gz to local cache.
Copying duplicity-new-signatures.20190905T050004Z.to.20190906T050005Z.sigtar.gz to local cache.
Copying duplicity-new-signatures.20190906T050005Z.to.20190907T050005Z.sigtar.gz to local cache.
Copying duplicity-new-signatures.20190907T050005Z.to.20190908T050004Z.sigtar.gz to local cache.
Last full backup date: Tue Sep 3 09:49:27 2019
Collection Status
-----------------
Connecting with backend: BackendWrapper
Archive dir: /home/ubuntu/.cache/duplicity/6a9fb8e3df936035e1be5ede96c0d7a7
Found 0 secondary backup chains.
Found primary backup chain with matching signature chain:
-------------------------
Chain start time: Tue Sep 3 09:49:27 2019
Chain end time: Sun Sep 8 01:00:04 2019
Number of contained backup sets: 7
Total number of contained volumes: 8
Type of backup set: Time: Num volumes:
Full Tue Sep 3 09:49:27 2019 2
Incremental Tue Sep 3 12:21:18 2019 1
Incremental Wed Sep 4 01:00:05 2019 1
Incremental Thu Sep 5 01:00:04 2019 1
Incremental Fri Sep 6 01:00:05 2019 1
Incremental Sat Sep 7 01:00:05 2019 1
Incremental Sun Sep 8 01:00:04 2019 1
-------------------------
No orphaned or incomplete backup sets found.
在这个具体的例子中,制作的菜单是这样的:
--------------------------------------------------------------------
- Select a restore point:
1) of contained backup sets: 8
2) number of contained volumes: 9
3) of backup set: Time: Num
4) Tue Sep 3 09:49:27 2019
5) Tue Sep 3 12:21:18 2019
6) Wed Sep 4 01:00:05 2019
7) Thu Sep 5 01:00:04 2019
8) Fri Sep 6 01:00:05 2019
9) Sat Sep 7 01:00:05 2019
10) Sun Sep 8 01:00:04 2019
11) Sun Sep 8 09:33:26 2019
但实际上应该只是:
--------------------------------------------------------------------
- Select a restore point:
1) Tue Sep 3 09:49:27 2019
2) Tue Sep 3 12:21:18 2019
3) Wed Sep 4 01:00:05 2019
4) Thu Sep 5 01:00:04 2019
5) Fri Sep 6 01:00:05 2019
6) Sat Sep 7 01:00:05 2019
7) Sun Sep 8 01:00:04 2019
8) Sun Sep 8 09:33:26 2019
(是的,9 月 8 日的双重备份是正确的……目前是这样)
所以......我一定是做错了,才显示那几行多余的内容......我该如何解决这个问题,我到底错在哪里?
(如果我可以简单地传递一个标志,那会容易得多--json
,但是目前尚未实现......)
答案1
我到底哪里错了?
if [ $_idx -ge 14 -a $_idx -le $_end ]
解析输出的整个方法通过从开头和结尾计算特定数量的非空行来解析输出。它非常脆弱,并且显然无法处理在您想要的行之前和之后返回不同数量的行。
您提供的 duplicity 输入比您预期的 14 个非空行多出 3 行,而所需数据之前是 14 个非空行。一种可能性是,此输入可能是 stdout 和 stderr 的混合,而您的代码仅读取 stdout。但是,我注意到,除行外,还有 14 个非空行。由于 duplicity 的输入也与备份日期的预期或实际输出不匹配,我怀疑您的示例的实际输入中Copying
只有三行。Copying
如果是这样,并且输出格式在所有情况下都相同,则如果duplicity collection-status
两次运行之间没有新的备份,您的代码可能会正常工作。但这也假设输出中不会出现新的意外,包括 duplicity 未来版本中可能出现的变化。
不要计数,而是扫描以“Full”或“Incremental”开头的行。额外的输出不太可能发生,而且也更简单。
这是一个重要的习惯总是双引号,"$variables"
除非您有意断词(例如您的 IFS 行)。如果您只做了最低限度,那么以后输入时很容易出现您最初没有预料到的意外断词。
此外,内置的 bash select
(参见help select
)是一种处理菜单的简单方法。
# get the backups information
_t=`duplicity collection-status "$1"`
# split the collection based on new lines
IFS=$'\n' _arr=($_t)
# loop over our resulting set and select lines
_ret_arr=()
for _l in "${_arr[@]}"; do
IFS=$' ' _temp_arr=($_l)
if [ Full = "${_temp_arr[0]}" -o Incremental = "${_temp_arr[0]}" ]; then
_d_string="${_temp_arr[1]} ${_temp_arr[2]} ${_temp_arr[3]} ${_temp_arr[4]} ${_temp_arr[5]}"
_ret_arr+=( "$_d_string" )
fi;
done
echo
echo '--------------------------------------------------------------------';
# make sure there are actually backups created, i.e. at least one line matched
if [[ -z "${_ret_arr[0]}" ]]; then
# it doesnt exist, show a message and exit
echo 'There are no backups for that account/app'
echo 'Please create the account, and make sure it matches the restore'
echo 'Account and App names'
echo '--------------------------------------------------------------------';
echo
exit 1;
fi
echo "- Select a restore point: "
select _t in "${_ret_arr[@]}"; do
# will keep asking until valid value given
[ -n "$_t" ] && break
done
echo
# convert the selected value to a epoch date and return it
_ret_date=$(date -d "${_t}" +"%s")