shell 如何将一个命令的多行输出作为n个参数传递给一个命令,而不是将n个命令传递给一个参数?

62lalag4  于 2023-06-06  发布在  Shell
关注(0)|答案(2)|浏览(169)

TL;DR

给定输入

a
b
c

我试图执行命令foo,每个输入都作为一个单独的参数(例如'n'个输入表示使用'n'个参数对foo的单个调用)...

foo a b c

我并不打算每个参数执行一次foo(例如:'n'个输入意味着'n'个对foo的调用,每个调用都有一个参数迭代)

# Not this!
foo a
foo b
foo c

这可以在eval的字符串连接之外完成吗?

摘要

我试图找到推荐的方法,将一个命令的多行输出作为单独的参数传递给第二个命令。需要说明的是,我并不打算每个参数执行一次第二个命令。我试图将所有参数传递给一个命令示例。
这一点演示起来容易解释起来难。
考虑一下这个shell命令,它有一个硬编码的三个swift源文件的列表(注意,有些文件有空格,并且在子文件夹中)……

xcrun -sdk macosx swiftc -o "$OUTPUT_FILE" "main.swift" "car.swift" "Models/Road Bike.swift"

它非常简单,并按预期执行。
但是……我正在尝试自动化,所以我希望源文件列表是递归find操作的结果。
下面是我开始使用的find命令...

find * -type f -name "*.swift"

执行将产生以下结果...

Models/Road Bike.swift
car.swift
main.swift

尝试1

因此,我的第一次尝试,我尝试了这个...

SOURCE_FILES=$(find * -type f -name "*.swift" | tr '\n' ' ')
xcrun -sdk macosx swiftc -o "$OUTPUT_FILE" $SOURCE_FILES

……但是没有用。我(错误地)认为这是因为文件名没有正确引用。

尝试2

由于上述原因,我将其更改为此以相应地 Package 每个文件名...

SOURCE_FILES=$(find * -type f -name "*.swift" | while read fn; do echo \"$fn\"; done | tr '\n' ' ')
xcrun -sdk macosx swiftc -o "$OUTPUT_FILE" $SOURCE_FILES

这确实正确地将引号添加到文件名中,但那时我才意识到我之前的错误...它没有把它当作单独的参数,每个文件名一个,而是把它当作一个带有嵌入引号的大文件名的单个参数(上次是一个没有嵌入引号的大文件名)。

尝试3 -成功!

好了,这时我意识到我可以使用蛮力,将我想要的命令构建为文字字符串,然后使用eval执行它。有了这些知识,我最终选择了这个...

SOURCE_FILES=$(find * -type f -name "*.swift" | while read file; do echo \"$file\"; done | tr '\n' ' ')
cmd='xcrun -sdk macosx swiftc -o "$OUTPUT_FILE" '$SOURCE_FILES
eval $cmd

……果然奏效了。但是...我不禁觉得这是一个又一个的解决方案。
是否有更简单的方法将find(或ls等)命令的输出作为单独的输入参数传递给compile(或任何其他)命令?不然怎么解决呢?推荐/首选的方法是什么?

  • 注意:我使用的是zsh,但如果它也兼容bash,那也很好。
hsgswve4

hsgswve41#

你太努力了。

find * -type f -name "*.swift" -print0 | xargs -0 xcrun -sdk macosx swiftc -o "$OUTPUT_FILE"
gzszwxb4

gzszwxb42#

第一个

将多行输出保存在数组中

将数组传递给所需的命令

示例- test

逐行运行

# cd into a test directory
cd `mktemp -d`

# generate list of files
touch file-{01..09}.txt

# save the list in an array + remove trailing newlines 
mapfile -t list < <(find -type f -name \*.txt)

# check the output
echo "${list[@]}"

# see the size of the array
echo "${#list[*]}"

# see indexes 
echo "${list[0]}"
echo "${list[1]}"
echo "${list[2]}"

# pass the array to a command you liked 
# for example substitute txt with TXT
sed 's/txt/TXT/g' <<< "${list[*]}"

# output
./file-09.TXT ./file-08.TXT ./file-07.TXT ./file-06.TXT ./file-05.TXT ./file-04.TXT ./file-03.TXT ./file-02.TXT ./file-01.TXT

这不是仍然一个接一个地对每个参数起作用吗?
A.不是array负责一一操作,而是我们使用的command有what和which行为。
例如,如果你将数组传递给echo,它就可以工作。因为echo接受N个参数,所以没有限制。
另一方面,如果将数组传递给diff,它将不起作用,因为它只接受两个参数。

echo测试

echo ${list[@]}
./file-09.txt ./file-08.txt ./file-07.txt ./file-06.txt ./file-05.txt ./file-04.txt ./file-03.txt ./file-02.txt ./file-01.txt

diff测试

diff  ${list[@]}
diff: extra operand './file-07.txt'
diff: Try 'diff --help' for more information.

相关问题