我试图先echo
文件名,然后直接sqlcmd
,但我根本不知道如何以有效的方式连接语句。
我试过:
- 创建一个新函数(显然在纯shell bash中不能这样做(
- 用分号分隔(转义和不带(
- 使用double&;按照这个例子
请提供任何提示。
find "./src/ALs/Database/SQL" -iname "*.sql" | sort -n | xargs -0 -I % sh -c 'echo % && sqlcmd -S $SQL_HOST -d Database -U $SQL_USER -P $SQL_PWD -i %'
我认为,如果您从xargs中删除-0
,它将达到您的预期。该标志用于空字节分隔的输入,而您传递的是换行符分隔的输入。
要在整个管道中使用空字节分隔的记录,请使用find ... -print0
、sort -z
和xargs -0
。这是通过管道传递记录的最稳健的方法(无论文件名是什么,它都不会中断(。
find "./src/AdviserLinks/Database/SQL" -iname "*.sql" -print0 |
sort -zn |
xargs -0 -n1 sh -c 'echo "$0" &&
sqlcmd -S "$SQL_HOST" -d WebSupportDatabase -U "$SQL_USER" -P "$SQL_PWD" -i "$0"'
这假设$SQL
变量是export
环境变量。
我已经用-n1
替换了-I %
,它将一次处理一条记录。每个文件名作为$0
传递给sh
,可以安全使用;记录的内容没有被解释为shell语法的风险,就像您尝试的-I %
一样。请注意,这意味着为每个文件调用一个单独的子shell,并且使用Charles的答案中的循环会更有效。
至于使用单独的语句与&&
,这取决于您是否希望第二个命令的执行以第一个命令的成功为条件。
旨在将安全性和性能结合起来(对于命令行中的sql文件列表,仅调用sh
一次(:
find "./src/AdviserLinks/Database/SQL" -iname "*.sql" -print0 |
sort -zn |
xargs -0 sh -c '
for arg do
echo "$arg"
sqlcmd -S "$SQL_HOST" -d WebSupportDatabase -U "$SQL_USER" -P "$SQL_PWD" -i "$arg"
done
' _
注:
- 我们根本没有对
xargs
使用-I
参数。我们不使用sigil,而是让xargs将尽可能多的项连接到sh
的参数列表的末尾 - 在
sh
命令中,默认情况下,for arg do
在"$@"
上循环;因此,它将$1
、$2
等依次分配给名为arg
的变量,这样sh
的一个副本就可以处理多个SQL文件 - 我们让
SQL_HOST
、SQL_USER
和SQL_PWD
等值的所有扩展都由子shell执行,而不是试图在父shell中执行(请注意,这确实要求将这些值导出到环境中,而不仅仅设置为进程本地shell变量(。这一更改意味着,可能具有对shell有意义的字符的SQL密码不会有被解析为语法的风险