我可以将参数列表从文本文件间接到 bash 脚本吗?

我可以将参数列表从文本文件间接到 bash 脚本吗?

我正在考虑ls @files.lst做一些ls [contents of files.lst]想做的事情,包括通配符。

我想我记得上面的语法(at-sign,文件名)来自某个地方(也许是上一个冰河时代之前某个时间的旧数字操作系统?)。搜索 Bash、间接、参数、列表……的排列并没有给我带来任何帮助。我知道有一些方法可以将其写入(每个?!)脚本中,但是 bash 是否已经以某种更通用的方式实现了它,而我至今还没有这样做?

更新:这是针对 BSD/Darwin (ATM) 的,但我也很欣赏更一般的答案。我使用的是 Mac,如果现在还不是很明显的话,那么计算效率低下不会妨碍其他人,而且工作量也很小。更有趣的是能够使用现有的 shell 脚本来从命令行接收命令,而且大多数情况下,它们会这样做。

答案1

如果您想对文本文件的每一行执行某些操作,通常有两种方法。

  1. 逐行读取文件并对循环体中的行执行您需要执行的操作:

    while IFS= read -r pathname; do
        ls -d -- "$pathname"
    done <files.list
    

    上面的代码从文件中读取行files.listls -d --在每一行上执行。

    有关的:

  2. 使用使循环隐含的实用程序,例如xargs或 GNU parallel

    xargs -I {} -- ls -d -- {} <files.list
    

    该代码的作用与上面的循环相同,但用于xargs执行ls -d --从 读取的每个参数files.list。参数是一行,如果换行符被转义,则可以在其中嵌入换行符(引号也会被处理,因此必须对它们进行转义才能保留)。

    xargs -- ls -d -- <files.list
    

    上面的代码将ls -d --同时运行文件中尽可能多的参数。需要引用包含嵌入制表符或空格的参数,并转义各个嵌入的换行符和引号。

    GNUparallel实用程序比 GNU 实用程序更通用,xargs并且允许对执行的作业进行更多控制。

  3. 由于 shell 通常是您可以选择用于处理数据的最慢的语言,因此如果您需要执行除为文件中的每一行执行命令之外的其他操作,那么最好使用一种更容易执行此操作的语言来执行此操作。此类语言的示例:

    • awk
    • 珀尔
    • Python

在任何一种情况下,由于您在文件中存储以换行符分隔的路径名,因此您没有资格使用包含换行符的路径名(这些在 Unix 系统上是合法的),除非充分引用以供使用xargs(请参阅xargs手册)。

答案2

读取命令的输出man xargs,然后执行以下操作:

xargs -r <files.lst somecommand

xargssomecommand用尽可能多的项目填充 的命令行,并根据需要files.lst使用尽可能多的执行。somecommandxargs --show-limits </dev/null

您还可以使用一次xargs将文件名提供给1 个:somecommand

xargs -r -n 1 <files.lst somecommand

答案3

学习 Bash 的细节;www.tldp.org-> Bash 指南

$ man bash讲述了一些细节,但形式简洁。

现在绕过上面那些有大部分细节的来源;
一个非常简单且不完整的答案:

$ ls -l $(cat file)
... 将读取file该文本并将其插入为 的参数ls,用空格 (SP) 字符替换 LF (\n) 字符。

请注意,除非您在这里使用技巧,否则不太可能发生通配符。

注意另一个问题;如果文件中的任何行包含一个或多个空格,则该行上的单词将成为ls.

特定命令(是否特定于 bash)是否可以从文件中获取参数会有所不同;
man command_name通常会告诉指定命令的详细信息command_name(将其替换为真实的命令名称)。

答案4

zshshell 中:

cmd -- $(<file)

使用默认值$IFS, 会将每个空格/TAB/NL/NUL 分隔的单词传递到fileto cmd(其中(来自 ksh)扩展为不带尾随换行符$(<file)的内容,并且当不加引号时会受到 IFS 分割 1)。file

cmd -- ${(f)"$(<file)"}

将每个非空行的内容作为单独的参数传递给cmd(其中f参数扩展标志在换行符上分割,也称为行feed,并且空参数被丢弃,因为扩展未被引用)。

替换f0在 NUL 而不是 NL 上进行拆分。

cmd -- "${(Q@)${(zZ[n])$(<file)}}"

将解释文件中的 zsh 样式引用,并使用z标志进行引用感知标记化,Z[n]对其进行调整,以便换行符仅被视为分隔符,Q删除引号并@与引用结合保留空元素。

例如,在file类似的情况下:

'' "foo bar"

whatever $'\n'

作为printf '<%s>\n'命令,这将给出:

$ printf '<%s>\n' $(<file)
<''>
<"foo>
<bar">
<whatever>
<$'\n'>
$ printf '<%s>\n' ${(f)"$(<file)"}
<'' "foo bar">
<whatever $'\n'>
$ printf '<%s>\n' "${(Q@)${(zZ[n])$(<file)}}"
<>
<foo bar>
<whatever>
<
>

1 在 Korn shell(或 bash)中,它将受到 IFS 分割的影响通配符,您通常不希望出现这种情况,除非这些词恰好意味着通配符模式。另请注意,ksh/bash 默认情况下不会在 NUL 上进行拆分(并且通常无法处理这些问题)。

相关内容