我正在编写一个具有以下内容的基本脚本:
LOG_COMMAND=">/tmp/something.log 2>&1"
if [ "${VERBOSE}" == "y" ]; then
LOG_COMMAND="2>&1 | tee /tmp/something.log"
fi
问题在于,当我在脚本中使用LOG_COMMAND
变量时,它会被单引号引起来。例如:
set -v
docker build -t test:test . ${LOG_COMMAND}
set +v
我得到以下输出:
$ /bin/bash testing.sh -v
+ docker build -t test:test . '2>&1' '|' tee /tmp/something.log
"docker build" requires exactly 1 argument.
See 'docker build --help'.
如何防止包含单引号?
答案 0 :(得分:3)
简单而强大的解决方案是将要重用的代码放在函数中,而不是变量中:
log() {
if [ "$VERBOSE" = "y" ]
then
"$@" 2>&1 | tee -a /tmp/something.log
else
"$@" >> /tmp/something.log 2>&1
fi
}
log docker build -t test:test .
您看到的单引号不会以任何方式添加,它们只是bash的符号,向您显示该值是文字字符串,而不是命令语法的一部分。 “删除”它们不会改变事实,因为它们只是未解释的字符串,而whoami() { echo root; }
会使您成为超级用户。
如果它有助于将内容放到上下文中,则Java具有相同的“问题”和相同的首选解决方案:
// Works
System.out.println("hello world".replaceAll("hello", "goodbye"));
// Fails
String replacer = ".replaceAll(\"hello\", \"goodbye\")";
System.out.println("hello world" + replacer);
答案 1 :(得分:2)
变量存储数据,而不存储代码;除非您要进行evil操作,否则不能为此目的使用变量。相反,请提前执行间接操作:
case $VERBOSE in
y) exec 2>&1 > >(tee /tmp/something.log)
*) exec >/tmp/something.log 2>&1
esac
...将重定向stdout和stderr,以查找它们下面的所有代码。如果只想让 some 代码受此约束,请设置另一对有条件重定向的文件描述符:
case $VERBOSE in
y) exec 3> >(tee /tmp/something.log)
*) exec 3>/tmp/something.log
esac
......,然后将要遵守这些记录规则的命令重定向到该FD:
something_that_should_be_logged >&3 2>&3