在bash脚本中读取并传递参数给脚本

4

我有一个问题,但是很遗憾没有找到答案。我该如何将另一个命令的结果作为参数传递给脚本呢?例如:

 ls | ./myscript.sh

我想将 ls 命令的结果传递给脚本 myscript。如果我执行上述命令并且脚本如下:
#!/bin/bash
read some
for arg in $@
do 
     grep $some $arg
done

那么它并没有等待读取some变量,变量some的值来自于传递给ls命令的结果?这实际上是如何工作的?我想要做以下事情:将文件名(使用ls命令)添加到脚本中,然后让用户输入一些字符串,并打印包含输入单词的每一行。 我不知道为什么上面的代码不起作用。谢谢。


1
请使用正确标记的代码块格式化您的问题(使用反引号和工具栏上的 {} 按钮)。此外,请提供涉及读取输入的 myscript.sh确切内容,并显示可能的输出/结果以及您想要获得的内容。 - Etan Reisner
你是想从键盘而不是从ls中填充“some”吗?read只是从标准输入读取,而在所示的管道中,标准输入是ls的输出,而不是终端。 - chepner
1
FYI -- 在编程中程序化地使用ls命令的输出是一个非常糟糕的想法。请参考 http://mywiki.wooledge.org/ParsingLs - Charles Duffy
1
此外,for arg in $@for arg in "$@"(或者仅仅是 for arg,因为 "$@"for 循环的默认目标)并不相同。如果你想在命令行上传递参数,那么你需要使用后者。 (管道将内容放在 stdin 上,而不是命令行,这是一个不同的问题)。在这种情况下,用法应该是 ./myscript * 来传递当前目录中的所有文件。 - Charles Duffy
我会假设您帖子中的 ls 只是随意示例,而您只想要从 myscript 中读取任何管道输出。您可以创建一个 while read 循环,并它将从 stdin 中读取。 - alvits
显示剩余2条评论
2个回答

4

xargs是将标准输入转换为命令行参数的实用程序。

朴素地说,您可以执行以下操作:

ls | xargs ./myscript.sh

然而,对于文件名中嵌入空格的情况,这种方法无法按预期工作,因为它们将被分成多个参数。
请注意,./myscript.sh $(ls) 也存在同样的问题。

如果您的 xargs 实现支持非标准的 -0 选项来解析以 NUL 分隔的输入,您可以按照以下方式修复此问题:

printf '%s\0' * | xargs -0 ./myscript.sh

否则,可以使用以下方法,但前提是文件名中没有嵌入 " 字符(或嵌入换行符):
printf '"%s" ' * | xargs ./myscript.sh

由于这种情况下您的标准输入来自于文件名,因此您可以使用find命令,在其中已经内置了xargs功能:

find . -type f -maxdepth 1 -exec ./myscript.sh {} +
  • 请注意,find . -type f -maxdepth 1 本质上ls 做的相同,但存在细微差别,特别是每个匹配的文件名都将以 ./ 为前缀,并且文件名可能没有排序。
  • -exec ./myscript.sh {} + 调用你的脚本,并将尽可能多的文件名({})放在单个命令行上(+),就像 xargs 所做的一样,通常是所有的文件名。

请注意,xargsfind ... -exec ... + 可能 导致指定命令的多次调用,如果不是所有参数都适合于单个命令行。
然而,在现代平台上允许多长的命令行的情况下,这种情况很少发生-只有当你的目录中有大量文件和/或它们的名称非常长时才会发生。


1
您可以运行以下命令:

./myscript.sh $(ls)

这将提示用户输入“some”变量,并通过grep查找用户输入值所包含的文件。

然而,这种方法可能会遇到问题,因为空格和其他字符可能导致您的循环接收到无效的输入。

考虑到这一点,根据您的脚本复杂程度,您可能还想研究一下findxargs来实现类似的功能。例如:

find . -type f -print0 | xargs -0 grep "test"


./myscript.sh $(ls) 很诱人,但是文件名中有空格时会出错。 xargs -0 是一般情况下最健壮的方法,但请注意,如果您已经在使用 find,则可以仅使用 find,使用其 -exec 主要功能:find . -type f -exec grep "test" {} + - mklement0
没错。我从“如何使用bash将参数作为命令输出”这个角度回答了他的问题,而不是特定实现的find / grep脚本。但是,我同意你的观点,这也是为什么我给了他find / xargs指针,以指导他朝着正确的方向前进。 - Matt Barlow
1
请不要推荐使用未加引号的命令替换作为命令行参数,作为“如何使用bash传递参数作为输出”的通用解决方案,因为它不是。 如果您仍然想要推荐它,请在您的答案中非常清楚地指出,它只会在以下情况下起作用: (a) 逻辑输出标记没有嵌入空格(因为由于单词分割,标记边界将丢失),以及 (b) 如果输出标记不恰好看起来像全局通配符,因为路径名扩展将发生(例如尝试 echo $(echo '*'))。 - mklement0
1
感谢您的反馈。我已经按照您的建议编辑了我的答案,加入了警告提示。 - Matt Barlow

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接