shell 编程,避免临时文件

shell 编程,避免临时文件

我经常编写遵循相同模式的 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

您有两个选择:

  1. 您检索数据一次(在您的示例中为getInfo)并将其存储在文件中。

  2. 每次都取数据,不存储在本地,即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

相关内容