我有一个基本的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
。我已经尝试过研究,但我能找到的只是如何运行带有重定向和管道的脚本,而不是如何在运行时使脚本本身保存。
如何显示脚本输出并将其保存为唯一的文件名?
答案 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.
只需输入script myfile.txt
。
执行您想要的任何shell命令。
完成后输入<Ctl-D>
。
瞧!您的会话将被写入&#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
在您找到它的确切字段中查找您的确切字符串会更安全。