使用"find"和"xargs"在shell脚本中运行多个命令



我试图先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 ... -print0sort -zxargs -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_HOSTSQL_USERSQL_PWD等值的所有扩展都由子shell执行,而不是试图在父shell中执行(请注意,这确实要求将这些值导出到环境中,而不仅仅设置为进程本地shell变量(。这一更改意味着,可能具有对shell有意义的字符的SQL密码不会有被解析为语法的风险

最新更新