如何将变量传递给使用“sh -c”运行的 shell 表达式?

如何将变量传递给使用“sh -c”运行的 shell 表达式?

我有以下脚本,它在看起来像这样的文件夹中运行:log_file/2020/04/30 此文件夹包含一个server.log文件。每个日期都有一个文件。

我的脚本

path_date=$(echo "$(pwd)" | grep -oP '\d+/\d+(/\d+)?')
date=${path_date//\//-}
echo date: $date


find ./ -name "server.log*" |  xargs -i sh -c 'filename=$(basename {}) && new_filename=${date}-$filename && echo $(readlink -f {}) ${new_filename}' >> ~/logs/server-logs.list

我希望输出文件~/logs/server-logs.list包含如下行

log_file/2020/04/30/server.log 2020-04-30-server.log

但它输出的是

log_file/2020/04/30/server.log -server.log

该变量$date在上下文中不存在sh -c

如何将变量从当前 shell 传递到用其运行的 shell 表达式sh -c

答案1

这个精彩的答案斯蒂芬·查泽拉斯在 Unix 和 Linux SE 上。
我不想重复,只想说必要的部分:

切勿嵌入{}shell 代码!否则会造成命令注入漏洞。

而是使用

xargs -I{} sh -c 'echo "$1";' xargs-sh {}

或者

find -exec sh -c 'echo "$1";' find-sh {} \;

名称xargs-sh/find-sh只是一个名称,可以是任何内容(您会看到_很多),但它会使错误更容易跟踪,因为这将是错误消息的一部分。


顺便说一句:使用 时find,最好使用-exec而不是管道到xargs。如果出于某种原因您仍要这样做,请使用 NUL 分隔的输出,以避免脚本在文件名包含换行符时阻塞,这种情况并不常见,但有效:

find ... -print0 | xargs -0 ...

关于如何添加$date到您的 sh -c 脚本:

单引号中的变量不会被扩展。读这个或者

但在这种情况下,将日期作为参数添加到sh -c脚本中在我看来更安全:

find -exec sh -c 'date="$1"; file="$2"; ...' find-sh "$date" {} \;

相关内容