Mit*_*ril 5 command-line bash scripts
我很好奇是否有一个函数/命令来处理循环管道?
\n\n很容易出现低于需求的情况
\n\n例如:
\n\n您需要找到一些与模式匹配的路径,将每个路径移动到另一个地方:
\n\n# 1.\nfind path_A -name \'*AAA*\' -exec mv -t path_B {} +\n\n# 2.\nfind path_A -name "*AAA*" -print0 | xargs -0 -I {} mv {} path_B \n
Run Code Online (Sandbox Code Playgroud)\n\n人们会感到困惑,
\n\n-t
(我的意思是,通过 [for 循环管道] 你可以使用mv {} some_path
\xef\xbc\x8cjust like what you wrote without pipe )ls ... mv -t path_B {} +
,或者ls | xargs -0 -I {} mv {} path_B
换句话说,为什么我更改为另一个命令后它不起作用?mv
为7z
: 时失败find path_A -name \'*AAA*\' -exec 7z -t {} +
?注意:以上不是问题,只是示例!
\n\n我问这个问题是为了寻求一种常见且简单的方法来应对循环管道。\n是否有一种简单而常见的方法可以做到:
\n\n# 0\ncommand with option (usually you use a command like this)\n\n# 1\ncommand with option [for loop pipe] command with option | command with option\n# 2\ncommand with option [for loop pipe] command with option | command with option [for loop pipe] command with option\n# 3 \n....\n
Run Code Online (Sandbox Code Playgroud)\n\ncommand with option
因此,当您使用 [for Loop Pipe] 时,不需要进行更改。这样对于日常使用来说会方便很多。
我举的所有例子只是想说,当不同的命令有自己的风格来处理多行输入时,正常的方式会令人困惑,它需要exec
或xargs
或其他一些选项。如果我们有一个for pipe
命令可以使用选项连接两个命令。使用起来会很方便
我的意思是,如果您使用高级语言。例如蟒蛇,
\n\n# 0\ncommand with option (usually you use a command like this)\n\n# 1\ncommand with option [for loop pipe] command with option | command with option\n# 2\ncommand with option [for loop pipe] command with option | command with option [for loop pipe] command with option\n# 3 \n....\n
Run Code Online (Sandbox Code Playgroud)\n\n这是一个非常简单的示例,有很多缺陷,但它解释了我试图在 bash 命令中获取的内容。
\n我不确定这是否是对这个问题的直接回答(问题不止一个),但我认为您要求的是以下内容:
\nfor
使用命令替换循环或while
循环与进程替换。for
循环与$(command substitution)
命令替换允许命令的输出替换命令本身。for
我们可以通过这种方式将此功能与循环结合起来:
for item in "$(find . -type f)"\ndo\n echo "$item" | tee -a ./"file-list.txt"\ndone\n
Run Code Online (Sandbox Code Playgroud)\n while
循环与<(process substitution)
进程替换允许使用文件名引用进程\xe2\x80\x99s的输入或输出。我们可以while
借助内置函数将此功能与循环结合起来read
,如下所示:
while IFS= read -r item\ndo\n echo "$item" | tee -a ./"file-list.txt"\ndone < <(find . -type f)\n
Run Code Online (Sandbox Code Playgroud)\n在最后一部分中< <(find . -type f)
,第一个<
表示当前的标准输入loop
,并将<(find . -type f)
被视为文件。有关构造的更多信息,IFS= read -r line
您可以阅读St\xc3\xa9phane Chazelas 的这篇精彩文章。
您可以通过使用管道而不是进程替换来实现与上述相同的效果(但不首选此选项,因为它可能会导致错误):
\nfind . -type f | while IFS= read -r file\ndo\n echo "$file" | tee -a ./"file-list.txt"\ndone\n
Run Code Online (Sandbox Code Playgroud)\n 此外,我们可以将循环的输出通过管道或重定向到另一个命令或函数:
\nwhile IFS= read -r -d \'\' item; do\n # Compose the name of the new file\n DIR="$(dirname "${item}")"\n FILE_NAME="$(basename "${item}")"\n NEW_FILE_NAME="new-${FILE_NAME}"\n\n # move the file and suppress the potential output \n # of the \'mv\' command by redirecting it to a log file \n mv "${item}" "${DIR}/${NEW_FILE_NAME}" >>/tmp/mv-loop.log 2>&1\n\n # output the name of the new file in order to be processed \n # by the next (piped) command\n printf \'%b\' "${DIR}/${NEW_FILE_NAME}"\'\\0\'\ndone < <(find . -type f -print0) | xargs -0 -I{} 7z a -t7z "the_archive_name.7z" {}\n
Run Code Online (Sandbox Code Playgroud)\n请注意,在上面的示例中,到处都使用了空分隔符:
\nfind . -print0
,IFS= read -r -d \'\' item
-参考,printf \'%b\' a\'\\0\'b
-参考,xargs -0
(在这种情况下,我们实际上不需要-I{}
and{}
命令xargs
)。此示例将递归地移动(重命名)所有文件,但在存档中不会出现目录结构。
\n有没有一种简单又通用的方法可以做到
答:不,每个命令都不同。
关于您的问题:
您不需要-t
,但随后mv
将为每个文件运行,这会慢很多。你需要以而不是结束你-exec
的。\;
+
管道与循环无关for
,管道将标准输出从管道左侧发送到右侧的标准输入。从标准输入(或带有选项的文件)xargs
读取并使用从输入中获取的参数运行命令。-a
ls
没有-exec
选择。ls
可以与 一起使用xargs
,但不能与 一起使用xargs -0
,因为ls
没有 NULL 分隔输出的选项。这也是为什么你根本不应该使用ls
管道(文件名允许有换行符)。
对于mv
,-t
是目标目录,而对于7z
它是存档类型,你为什么认为它应该起作用?
对我来说,您似乎正在使用您并不真正理解的命令。这不适用于任何编程或脚本语言。
顺便说一句:您应该使用xargs
with-r
选项来避免空输入的问题。
归档时间: |
|
查看次数: |
15544 次 |
最近记录: |