我正在调试一个 shell 脚本,该脚本在一个系统上运行良好,但在另一个系统上失败。该脚本本质上是解压缩和解压存档的日志文件,然后在所包含的日志文件中查找给定的子字符串。
经过一些分析和调试,我现在发现在一个系统上嵌入的“basename $TAR_FILENAME”命令被正确执行(即执行反引号之间的命令,结果替换反引号之间的字符串部分)而在其他系统上,不会发生替换,而是插入字符串“basename <filename-here>”(包括反引号)。这当然会破坏该字符串的进一步处理,并且 grep 不起作用。
什么可能导致这种情况?可以在 bash 中启用/禁用反引号功能吗?我不知道有任何设置或开关允许打开/关闭该功能。或者有吗?
后来补充:这是脚本:
#!/bin/bash
pattern=$1
for f in *.tar.gz; do
echo "$f:"
tar -xzf "$f" --to-command 'echo "f:`basename $TAR_FILENAME` s:'"$pattern\""
done
Run Code Online (Sandbox Code Playgroud)
在一个系统上,这会产生如下行: f:localhost_access_log.2021-07-29.txt s:pattern
在第二个上,这会产生如下行: f:`basename ./localhost_access_log.2021-07-29.txt` s:pattern
两个系统都在 SLES-11 上(确实很旧......)。
tar 1.26 将命令传递给 shell(源代码):
argv[0] = "/bin/sh";
argv[1] = "-c";
argv[2] = to_command_option;
argv[3] = NULL;
priv_set_restore_linkdir ();
execv ("/bin/sh", argv);
Run Code Online (Sandbox Code Playgroud)
tar 1.27 对此进行了更改以跳过 shell,作为另一个修复的一部分(源代码):
if (wordsplit (cmd, &ws, (WRDSF_DEFFLAGS | WRDSF_ENV) & ~WRDSF_NOVAR))
FATAL_ERROR ((0, 0, _("cannot split string '%s': %s"),
cmd, wordsplit_strerror (&ws)));
execvp (ws.ws_wordv[0], ws.ws_wordv);
Run Code Online (Sandbox Code Playgroud)
由于 shell 负责处理反引号,因此它们将在 1.26 中解释,但在 1.27.1 中不解释。
tar 1.29 的行为已改回。