如何使脚本显示并将其自己的输出保存为唯一的文件名?

时间:2017-06-24 22:05:50

标签: linux bash

我有一个基本的I / O脚本我会根据用户输入使用一堆不同的输出来调用test.sh。基本示例如下:

echo "Enter username"
read USERNAME
grep $USERNAME /etc/passwd
grep $USERNAME /etc/group
echo "Done"
exit 0

我需要此脚本在运行时显示并保存所有输出。我理解如何使用tee管道单个命令来显示并保存到sh test.sh | tee new.txt这样的文件中,但我在如何使脚本本身在运行时显示它时保存其整个输出时感到很遗憾。

我还想让脚本在每次运行时保存为唯一的文件名,文件名为USERNAME-DATETIME.rpt。我已经尝试过研究,但我能找到的只是如何运行带有重定向和管道的脚本,而不是如何在运行时使脚本本身保存。

如何显示脚本输出并将其保存为唯一的文件名?

4 个答案:

答案 0 :(得分:1)

您可以使用exec从脚本中重定向所有后续输出(到stdout):

exec 1>"/path/to/$USERNAME-$(date -Is).rpt"

(在获得USERNAME后插入。)

如果您希望重定向stderr和stdout,请使用&快捷方式(仅限bash):

exec &>"/path/to/$USERNAME-$(date -Is).rpt"

编辑:请注意exec 1>file会将您的所有输出重定向到文件。要也在您的终端上显示(重复它),您可以将exec重定向与流程替换相结合:

exec &> >(tee "/path/to/$USERNAME-$(date -Is).rpt")

答案 1 :(得分:1)

您只需将代码括在方括号中,然后将其重定向到您生成的唯一文件名即可。 (这对于所有实际目的都是唯一的!)

#!/bin/bash

myuniquefilename="$( cut -c1-8 <( date "+%S%N" | md5sum ))"

echo "Enter username"
read USERNAME
{
    echo "Executing. ..."
    date 
    grep $USERNAME ./etc/passwd
    grep $USERNAME ./etc/group
} > ${myuniquefilename}.out

echo "Done"
exit 0

答案 2 :(得分:0)

您应该考虑script命令:

  

NAME

   script - make typescript of terminal session
     

概要

   script [options] [file]
     

说明

   script makes a typescript of everything displayed on your terminal.
   It is useful for students who need a hardcopy record of an
   interactive session as proof of an assignment, as the typescript file
   can be printed out later with lpr(1).

   If the argument file is given, script saves the dialogue in this
   file.  If no filename is given, the dialogue is saved in the file
   typescript.
  1. 只需输入script myfile.txt

  2. 执行您想要的任何shell命令。

  3. 完成后输入<Ctl-D>

  4. 瞧!您的会话将被写入&#34; myfile.txt&#34;。

答案 3 :(得分:-1)

作为the answer by @randomir的替代方案,适用于所有符合POSIX标准的shell:

# note that using "fifo.$$" is vulnerable to symlink attacks; execute only in a directory
# where you trust no malicious users have write, or use non-POSIX "mktemp -d" to create a
# directory to put the FIFO in.
fifo_name="fifo.$$"

mkfifo "fifo.$$"
tee "/path/to/$USERNAME-$(date "+%Y-%m-%dT%H:%M:%S").rpt" >"fifo.$$" &
exec >"fifo.$$" 2>&1 # redirects both stdout and stderr; remove the "2>&1" for only stdout

确保脚本执行完毕后rm -f "fifo.$$"

在整个脚本的上下文中,通过一些其他最佳实践修复,这可能如下所示:

#!/bin/sh
echo "Enter username: " >&2
read -r username

fifo_name="fifo.$$"
mkfifo "fifo.$$"
tee "/path/to/$username-$(date "+%Y-%m-%dT%H:%M:%S").rpt" >"fifo.$$" &
exec >"fifo.$$" # 2>&1 # uncomment the 2>&1 to also redirect stderr

# look only for exact matches in the correct field, not regexes or substrings
awk -F: -v username="$username" '$1 == username { print $0 }' /etc/passwd
awk -F: -v username="$username" '$1 == username { print $0 }' /etc/group

echo "Done" >&2 # human-targeted status messages belong on stderr, not stdout

rm -f "$fifo_name"

注意:

  • date -Is是一个GNUism,在BSD日期不可用,并且当然不能在POSIX平台上得到保证。因此,如果您不知道shell将运行在哪个平台上,则传递显式格式字符串是安全的。
  • grep将正则表达式作为子字符串查找 - 在查找jdouglas时可以找到用户jdoug,在查找{foo1bar时找到用户foo.bar 1}}(作为一个点是正则表达式中的通配符)。它还可以匹配不同字段中的信息(具有人名,主目录等的GECOS字段)。告诉awk在您找到它的确切字段中查找您的确切字符串会更安全。