我经常编写遵循相同模式的 KSH shell 脚本:
- (1) 检索一个或多个命令的输出
- (2) 使用 grep|cut|awk|sed 对其进行格式化,并将其打印到屏幕或文件中
为了做到这一点,我经常将 (1) 的输出存储在临时文件中,然后对该文件进行 (2) 中的格式化。
以该代码为例:
TMPFILE=file.tmp
# If tmpfile exists rm it.
[ -f $TMPFILE ] && rm -f $TMPFILE
for SERVICE in $(myfunc); do
getInfo $SERVICE > $TMPFILE # Store raw output in the TMPFILE
# I retrieve the relevant data from the TMPFILE
SERV_NAME=$(head -1 $TMPFILE | sed -e 's/ $//')
SERV_HOSTNAME=$(grep HOSTNAME $TMPFILE | cut -d "=" -f2)
SERV_ARGS=$(grep Arguments $TMPFILE | cut -d ":" -f2)
print $SERV_NAME $SEP $SERV_HOSTNAME $SEP $SERV_ARGS
rm -f $TMPFILE #rm the TMPFILE in vue of next iteration
done
有没有办法使用管道、重定向等来避免每次将文件写入磁盘?
如果有帮助,我正在使用 ksh 版本 M-11/16/88i
答案1
在我看来,您的代码完全合理地使用了临时文件。我会坚持使用这种方法。唯一真正需要改变的是创建临时文件的方式。使用类似
TMP=$(tempfile)
或者
TMP=$(mktemp)
或者至少
TMP=/tmp/myscript_$$
这样,您就不会让名称被轻易预测(安全)并排除同时运行的多个脚本实例之间的干扰。
答案2
您可以使用变量:
info="$(getInfo $SERVICE)"
SERV_NAME="$(head -1 $TMPFILE <<<"$info" | sed -e 's/ $//')"
...
从man ksh
:
<<<word A short form of here document in which word becomes the
contents of the here-document after any parameter expan-
sion, command substitution, and arithmetic substitution
occur.
优点包括:
- 启用并行执行。
- 根据我的经验,这比临时文件快得多。除非您有太多数据以至于最终需要交换,否则速度应该会快几个数量级(仅排除高清缓存缓冲区,对于小数据量来说,这可能会快一些)。
- 其他进程或用户无法弄乱您的数据。
答案3
您有两个选择:
您检索数据一次(在您的示例中为
getInfo
)并将其存储在文件中。每次都取数据,不存储在本地,即
getInfo
每次调用
我没有看到创建临时文件以避免重新处理/重新获取的问题。
如果您担心将临时文件留在某个地方,您可以随时使用trap
以确保删除它,以防脚本被终止/中断
trap "rm -f $TMPFILE" EXIT HUP INT QUIT TERM
并用于mktemp
为临时文件创建唯一的文件名。
答案4
构造 shell 赋值语句并评估该输出,而不是生成文件。
for SERVICE in $(myfunc); do
eval $(getInfo $SERVICE |
sed -n -e '1/\(.*\) *$/SERV_NAME="\1"/p' \
-e '/HOSTNAME/s/^[^=]*=\([^=]*\).*/SERV_HOSTNAME="\1"/p' \
-e '/Arguments/^[^:]*:\([^:]*\).*/SERV_ARGS="\1"/p')
print $SERV_NAME $SEP $SERV_HOSTNAME $SED $SERV_ARGS
done
或者,如果您只想打印信息:
for SERVICE in $(myfunc); do
getInfo $SERVICE | awk -vsep="$SEP" '
BEGIN{OFS=sep}
NR == 1 { sub(/ *$/,""); SERV_NAME=$0 }
/HOSTNAME/ { split($0, HOST, /=/; SERV_HOSTNAME=HOST[2]; }
/Arguments/ { split($0, ARGS, /:/; SERV_ARGS }
END { print SERV_NAME, SERV_HOSTNAME, SERV_ARGS }'
done