我正在考虑ls @files.lst
做一些ls [contents of files.lst]
想做的事情,包括通配符。
我想我记得上面的语法(at-sign,文件名)来自某个地方(也许是上一个冰河时代之前某个时间的旧数字操作系统?)。搜索 Bash、间接、参数、列表……的排列并没有给我带来任何帮助。我知道有一些方法可以将其写入(每个?!)脚本中,但是 bash 是否已经以某种更通用的方式实现了它,而我至今还没有这样做?
更新:这是针对 BSD/Darwin (ATM) 的,但我也很欣赏更一般的答案。我使用的是 Mac,如果现在还不是很明显的话,那么计算效率低下不会妨碍其他人,而且工作量也很小。更有趣的是能够使用现有的 shell 脚本来从命令行接收命令,而且大多数情况下,它们会这样做。
答案1
如果您想对文本文件的每一行执行某些操作,通常有两种方法。
逐行读取文件并对循环体中的行执行您需要执行的操作:
while IFS= read -r pathname; do ls -d -- "$pathname" done <files.list
上面的代码从文件中读取行
files.list
并ls -d --
在每一行上执行。有关的:
使用使循环隐含的实用程序,例如
xargs
或 GNUparallel
:xargs -I {} -- ls -d -- {} <files.list
该代码的作用与上面的循环相同,但用于
xargs
执行ls -d --
从 读取的每个参数files.list
。参数是一行,如果换行符被转义,则可以在其中嵌入换行符(引号也会被处理,因此必须对它们进行转义才能保留)。xargs -- ls -d -- <files.list
上面的代码将
ls -d --
同时运行文件中尽可能多的参数。需要引用包含嵌入制表符或空格的参数,并转义各个嵌入的换行符和引号。GNU
parallel
实用程序比 GNU 实用程序更通用,xargs
并且允许对执行的作业进行更多控制。由于 shell 通常是您可以选择用于处理数据的最慢的语言,因此如果您需要执行除为文件中的每一行执行命令之外的其他操作,那么最好使用一种更容易执行此操作的语言来执行此操作。此类语言的示例:
- awk
- 珀尔
- Python
在任何一种情况下,由于您在文件中存储以换行符分隔的路径名,因此您没有资格使用包含换行符的路径名(这些在 Unix 系统上是合法的),除非充分引用以供使用xargs
(请参阅xargs
手册)。
答案2
读取命令的输出man xargs
,然后执行以下操作:
xargs -r <files.lst somecommand
xargs
将somecommand
用尽可能多的项目填充 的命令行,并根据需要files.lst
使用尽可能多的执行。somecommand
看xargs --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
在zsh
shell 中:
cmd -- $(<file)
使用默认值$IFS
, 会将每个空格/TAB/NL/NUL 分隔的单词传递到file
to cmd
(其中(来自 ksh)扩展为不带尾随换行符$(<file)
的内容,并且当不加引号时会受到 IFS 分割 1)。file
cmd -- ${(f)"$(<file)"}
将每个非空行的内容作为单独的参数传递给cmd
(其中f
参数扩展标志在换行符上分割,也称为行f
eed,并且空参数被丢弃,因为扩展未被引用)。
替换f
为0
在 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 上进行拆分(并且通常无法处理这些问题)。