Redhat 5.3 企业版
以下 Shell 脚本用于检查备份目录是否名为“ll_backup”,然后将其更改为等于文件 RESULT.VAR 的内容。result.var 文件被复制到另一个目录以用于日志记录。我在测试环境中运行了此脚本,但在生产中它出现了一个奇怪的错误,我无论如何也想不通!
脚本:
#!/bin/bash
#!/bin/cat
# Restores original directory name for next LogLogic Update
#TCJ 6/1/09
declare RESULT
declare FILE
FILE=result.var
cd /home/nb-backup/backups/nb-st3000/ll_bkup_65.99.220.172/
if [ -d ll_bkup ]
then
cat result.var | while IFS=: read RESULT
mv "ll_bkup" "$RESULT"
mv result.var /home/storegrid/scripts/results/result-`date +%y%m%d%s`.var
else
exit 0
fi
exit 0
结果:
nb-script-restorellbackup.sh:第 14 行:意外标记
else' nb-script-restorellbackup.sh: line 14:
else附近有语法错误
答案1
存在许多问题,从轻微问题到严重问题不等(所有严重问题都与“cat...while...read”行有关)。让我按顺序介绍一下:
- 正如丹尼斯·威廉姆森 (Dennis Williamson) 指出的那样,“#!/bin/cat”和“declare...”行没有任何作用。
- 您在顶部附近将 FILE 设置为 result.var,但从未使用过此变量。假设它旨在允许您仅在一个地方更改文件名,则应将对 result.var 的所有其他引用替换为“$FILE”
- while 语句需要“do...done”——或者说,如果您确实需要 while 语句的话,它确实需要。由于您只从文件中读取一个 RESULT,因此不需要循环。
- 由于“读取 RESULT”是管道的一部分,因此它在子 shell 中运行,并且当该子 shell 退出时,它设置的 RESULT 值将丢失。您可以使用类似“读取 RESULT <"$FILE"”的命令来修复此问题。
- 那里的“IFS=:”位是做什么用的?它在读取命令的持续时间内将内部字段分隔符设置为“:”,但由于您只读取一个字段(RESULT),因此它所做的唯一事情就是从 result.var 读取的内容中修剪前导或尾随冒号。如果您想忽略冒号后的所有内容(即仅使用 result.var 中第一个以冒号分隔的字段),则应改用“IFS=: read RESULT IGNOREDJUNK”。
- 除非您实际上试图修剪/解析 result.var 的内容,或者需要多次使用它,否则您根本不需要将其读入变量;只需使用“mv "ll_bkup" "$(cat "$FILE")"”。但我声称您想再次使用它(见下文)。
- 该脚本相当脆弱,因为它不会检查以确保 result.var 存在(并且由于脚本移动了该文件,如果连续运行两次,则第二次肯定会失败);同样,它在尝试将 ll_bkup 重命名为“$RESULT”之前不会检查它是否已经存在,从而可能导致不可预测的结果。
- 说到这,您的描述说 result.var 被复制了,但实际代码移动了它。哪个是预期的行为?
- 最后,“else...exit 0”部分不会执行任何操作,而最后的“exit 0”无论如何也不会执行任何操作。
抱怨,抱怨,抱怨...无论如何,这是我建议的重写:
#!/bin/bash
# Restores original directory name for next LogLogic Update
#TCJ 6/1/09
FILE=result.var
cd /home/nb-backup/backups/nb-st3000/ll_bkup_65.99.220.172/
if [ -d ll_bkup -a -f "$FILE" ]; then
read RESULT <"$FILE"
if [ ! -e "$RESULT" ]; then
mv "ll_bkup" "$RESULT"
mv "$FILE" /home/storegrid/scripts/results/result-`date +%y%m%d%s`.var
fi
fi
exit 0
答案2
答案3
您需要将该行更改为如下所示:
cat result.var | while IFS=:; do read RESULT; done
在我cat
看来read
,它将 $RESULT 设置为等于文件“result.var”内容最后一行的第一个字
并删除此行:
#!/bin/cat
因为它什么也没做。
declare
在这种情况下您确实不需要使用。
在日期命令周围使用$()
。这样更易读,必要时还可以更轻松地嵌套。