我有以下脚本,它在看起来像这样的文件夹中运行: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" {} \;