使用 read 从命令的输出中捕获多个变量

使用 read 从命令的输出中捕获多个变量

我有一个youtube-dl命令,运行时会输出两行新行,我试图将每一行捕获到变量中。

这是我目前所得到的,但由于某种我无法理解的原因,它只捕获第一行输出而丢弃第二行($audio为空)。

read -r video audio <<< "$(youtube-dl -g --youtube-skip-dash-manifest https://www.youtube.com/watch?v=-gcvAxJJiGo)"

我该如何修复它以使其捕获两个输入,或者是否有更可靠的方法来做到这一点?

答案1

read -r video audio将捕获第一个 ($IFS 分隔)单词进入“视频”和其余的进入“音频”

捕获两行的另一种方法是使用命令分组和进程替换:

{
  read -r video
  read -r audio
} < <(
  youtube-dl -g --youtube-skip-dash-manifest "$url"
)

之间的空格< <(很重要:a<(process substitution)就像一个文件,所以您可以使用它<来重定向来自文件的输入。


我突然想到:另一种阅读方式输出行数是个mapfile命令:

mapfile -t lines < <(youtube-dl ...)
declare -p lines  # just to inspect the array contents

video=${lines[0]}
audio=${lines[1]}

答案2

read按设计读取一行。读两行最简单的方法是使用read两次。

exec 3< <(youtube-dl -g --youtube-skip-dash-manifest 'https://www.youtube.com/watch?v=-gcvAxJJiGo')
IFS= read -r -u3 video
IFS= read -r -u3 audio
exec 3>&-

read -u不可移植,既不是<(…)。它们在 Bash 中工作,并且您的问题被标记,因此它们应该适合您。

注意,我使用单引号括住包含的字符串?,以防您有一个目录https:/www.youtube.com/和一个匹配的文件。这仅仅是有可能的,但仍然引用不应被视为通配符的通配符在任何 shell 中都是很好的做法。比较Zsh 中发生了什么

空的IFS 总体来说是正确的,当您想读一行时。

其他答案不用exec,很好。这是我的个人喜好在工具使用之前直观地设置输入(比较这个答案)。不幸的是,<(…) { …; }不起作用。有了exec我可以做到。

或者我可以通过管道传输youtube-dl到脚本的其余部分来完成此操作。

youtube-dl -g --youtube-skip-dash-manifest 'https://www.youtube.com/watch?v=-gcvAxJJiGo' \
| {
IFS= read -r video
IFS= read -r audio
}

通常,Bash 在子 shell 中运行{ … }片段,因此变量在 之后将不复存在}shopt -s lastpipe可以更改此设置(如果作业控制未处于活动状态)。如果没有lastpipe(不可移植),整个方法是可移植的,但您需要运行使用{ }块内变量的所有内容,因为您不知道它是否是子 shell(POSIX 允许这两种行为)。请注意,块内的 stdin 来自youtube-dl;如果块内的任何内容需要使用整个脚本的 stdin,那么您可能需要使用 来exec处理描述符。

另一种可移植的方法是这样的:

input="$(youtube-dl -g --youtube-skip-dash-manifest 'https://www.youtube.com/watch?v=-gcvAxJJiGo')"
video="$(printf '%s\n' "$input" | head -n 1)"
audio="$(printf '%s\n' "$input" | head -n 2 | tail -n 1)"

您可以使用或来代替head和来隔离右线。tailsedawk

请注意,此解决方案不使用read。如果您需要的功能,那么这不是办法。不过,在这种特殊情况下,read您似乎不需要的功能。read

即使youtube-dl非常快,我也不建议video="$(youtube-dl … | head -n 1)"加上audio="$(youtube-dl … | …)"。如果videoaudio来自同一个input,来自 的同一个 调用youtube-dl,那么它们就与工具允许的一样连贯。否则它们可能不连贯。坦率地说,我不知道它们可能有多不连贯(如果有的话);但我知道一般来说最好查询一次(例如date +%H:+%M应该始终连贯;date +%H; date +%M如果你在整整一个小时之前运行它,你会感到惊讶)。

相关内容