我有一个文件,其中包含一长串文件名(带有完整路径)。我还有一个程序想要多次运行,使用此列表中的一个和一个文件名作为参数。遗憾的是,我想运行的程序是一个自制的脚本;所以只能采取一一次输入文件名,并且它不能接受来自标准输入(如文件名列表) - 因此不可能进行管道或输入重定向。
我需要的是一个将运行的命令其他命令(我的脚本),使用文件中的行作为参数。
类似于find
-action -exec
...( find . -name "*.txt" -exec command \;
)。我想我其实可以在这里使用find
,但我想对输入文件进行排序......
所以我需要的是这样的:
for_each_command1 -f 文件列表 -c './my_command {}' for_each_command2 -f 文件列表 -exec ./my_command {} \; for_each_command3 -c './my_command {}'我处理此类任务的常用方法是
$ wc -l 文件列表 第232章 $ for (( i=1;我愿意 > ./my_command "`sed -n "${i}p" 文件列表`" > 完成sed
- 不幸的是,有很多开销而且不太漂亮(但它做工作...):
那么是否有内置的命令或 shell 来处理这样的事情呢?
答案1
方便,xargs -I
完全符合您的要求:
$ xargs <my_file_list.txt -I filename ./my_command "filename"
-I replace-str Replace occurrences of replace-str in the initial-arguments with names read from standard input. Also, unquoted blanks do not terminate input items; instead the separator is the newline character. Implies -x and -L 1.
这意味着它只需要一个以换行符分隔的输入行,并将其作为单个参数调用您的命令。除了换行符之外,没有任何内容被视为分隔符,因此空格和其他特殊字符都可以。
请注意,如果您想在文件名中允许换行符,则 nul 终止符(根据通配符的答案)也将在文件中起作用。
答案2
我假设您的文件列表存储在名为“filelist.txt”的文件中,每个文件名位于一行中。然后您可以使用每一行作为参数来调用脚本,如下所示:
while read name; do
./yoursrcipt.sh "$name"
done <filelist.txt
答案3
我通常更喜欢便携式(POSIX)解决方案,但是简单、明显这里的答案是使用 GNU 扩展来让你的生活更轻松:
find . -type f -name '*.txt' -print0 | sort -z | xargs -n1 -r0 ./mycommand
这使用空字节作为文件名之间的分隔符,这很重要,因为文件名可以包含任何字符,包括换行符。
(斜杠也被保留,因为它们是路径组件分隔符,但在这种情况下这并不重要,因为您不能将它们用作文件分隔符。)
答案4
$ cat baard.in
/path/to/some space file
/some tabbed/some tabbed file
/path to/genericfile
/path/to/regular.file
/path/to/exciting!/file!
/path/to/(parenthetical)/file.txt
$ cat my_command
#!/bin/sh
printf "my_command: %s\n" "$1"
由于 awk 已经解析行,因此您可以使用它对每条记录调用命令,请小心引用参数:
$ awk '{system("./my_command '\''" $0 "'\''");}' < baard.in
my_command: /path/to/some space file
my_command: /some tabbed/some tabbed file
my_command: /path to/genericfile
my_command: /path/to/regular.file
my_command: /path/to/exciting!/file!
my_command: /path/to/(parenthetical)/file.txt
但是,如果输入中存在单引号,则 awk 命令会失败,例如:
/books/Hitchhiker's Guide to the Galaxy.epub
如果你有 bash 可用,你可以使用:
$ readarray -t paths < baard.in
$ for((i=0;i < ${#paths[*]}; i++)); do ./my_command "${paths[i]}"; done
my_command: /path/to/some space file
my_command: /some tabbed/some tabbed file
my_command: /path to/genericfile
my_command: /path/to/regular.file
my_command: /path/to/exciting!/file!
my_command: /path/to/(parenthetical)/file.txt
my_command: /books/Hitchhiker's Guide to the Galaxy.epub
或者在 ksh93 中(向吉尔斯的回答在这里用于手动实现 readarray):
$ IFS=$'\n'; set -f
$ paths=( $(< baard.in) )
$ unset IFS; set +f
$ for((i=0;i < ${#paths[*]}; i++)) do ./my_command "${paths[i]}"; done
my_command: /path/to/some space file
my_command: /some tabbed/some tabbed file
my_command: /path to/genericfile
my_command: /path/to/regular.file
my_command: /path/to/exciting!/file!
my_command: /path/to/(parenthetical)/file.txt
my_command: /books/Hitchhiker's Guide to the Galaxy.epub