gpt4 book ai didi

linux - 管道传输时,没有此类文件或目录。每个命令分别工作,但在管道传输时则不行

转载 作者:太空狗 更新时间:2023-10-29 11:36:25 26 4
gpt4 key购买 nike

我有2个文件夹:folder_afolder_b。在这些文件夹中的每个文件夹中都有一堆文件。我正在尝试使用sed将所有这些文件移出这些文件夹,并移至我当前所在的当前工作目录中。

我的文件夹结构如下所示:

mytest:
a:
1.txt
2.txt
3.txt
b:
4.txt
5.txt

我尝试使用的命令是:
find . -type d ! -iname '*.*'  # find all folders other than root
| sed -r 's/.*/&\/*/' # add '/*' to each of the arguments
| sed -r 'p;s/.*/./' # output: a/* . b/* .
| xargs -n 2 mv # should be creating two commands: 'mv a/* .' and 'mv b/* .'

不幸的是我得到一个错误:
mv: cannot stat './aaa/*': No such file or directory

当我尝试其他策略(使用ls而不是mv)时,我也会遇到相同的错误:
for dir in */; do
ls $dir;
done;

即使我使用sed将每个目录名称中的空格替换为'\',或用引号将目录名称括起来,我也会遇到相同的错误。

我不确定这两个示例是否与我对bash的误解有关,但它们似乎都表明我对bash如何将一个命令的输出转换为另一命令的输入不了解。

谁能对此有所启发?

最佳答案

更新:完全重写。

正如@EtanReisner和@melpomene指出的那样, mv */* .或更具体地说,mv a/* b/* .是最简单的解决方案,但是您声明这部分是一种学习练习,因此其余答案显示了一个有效的基于find的解决方案,以及解释了原始命令的问题。

一个有效的基于find的解决方案

通常,如果可行,最好让find自己完成工作,而不涉及其他工具; find-exec操作类似于内置的xargs{}表示手头的路径(带有终止符\;)/所有路径(带有+):

find . -type f -exec echo mv -t . {} +

为了安全起见,他只会打印将要执行的 mv命令;删除 echo以实际执行它们。

这将执行单个[1] mv命令,所有匹配的文件都传递到该命令,并且 -t .将它们全部移至当前目录。

[1]如果生成的命令行过长(这不太可能),则将其拆分为多个命令,就像 xargs一样。

对文件( -type f)进行操作会绕过遍历的需求,因为 find随后会为您枚举所有文件(它也绕过了明确排除 .的需求)。

请注意,此解决方案适用于整个子树,而不仅仅是(立即)子目录。
考虑启用Bash 4的 globstar选项并使用 mv */** .是很诱人的,但这是行不通的,因为它还会尝试移动目录,而不仅仅是目录中的文件。

使用 -exec和进行 的重新编码:只有在+(所有路径的占位符)是{}之前的标记时,它才起作用。

由于您使用的是Linux,我们可以通过在+之前用mv选项指定-t的目标文件夹来满足此条件。在基于BSD的系统(例如OSX)上,您不能这样做,因为{}那里不支持mv,因此您必须使用终止符-t,这意味着对每个路径都调用一次\;,这显然要慢得多。

为什么您的命令不起作用:

正如@EtanReisner在注释中指出的那样, mv调用指定的命令时不(隐式)涉及 shell 程序,因此无法进行lobt_rstrong;您可以使用以下命令对此进行验证:
echo '*' | xargs echo  # -> '*' - NO globbing

如果我们忽略了通配符问题,则需要做一些额外的工作才能使xargs命令正确处理带有嵌入式空格(或其他shell元字符)的文件夹名称:
 find . -mindepth 1 -type d | 
sed -r "s/.*/'&'\/* ./" | # -> '<input-path>'/* . (including single-quotes)
xargs -n 2 echo mv # NOTE: still won't work due to lack of globbing

请注意,(组合)xargs命令现在如何生成单个输出行sed,输入路径包含在嵌入式单引号中,这是'<input-path>'/* .xargs识别为单个参数(即使它包含嵌入式空格)所必需的。
(如果文件名包含单引号,则您必须做更多的工作;还请注意,由于现在给定目录的所有参数都在一行上,因此可以使用<input-path>。)

还要注意如何使用xargs -L 1 ...(仅子目录级别或更低级别的处理路径)来跳过对-mindepth 1本身的处理。

使发生globbing的唯一方法使涉及的 shell 程序:
 find . -mindepth 1 -type d | 
sed -r "s/.*/'&'\/* ./" | # -> '<input-path>'/* . (including single-quotes)
xargs -I {} sh -c 'echo mv {}' # works, but is inefficient

请注意,使用.'xargs选项将每条输入行视为自己的参数(-I是输入的自选占位符)。
{}调用(默认)shell来执行生成的命令,在此情况下确实会发生globbing。

但是,总的来说,这效率很低:
  • 使用具有3个段的管道。
  • 为每个输入路径调用一个shell实例,它依次调用sh -c实用程序。

  • 将此与上面高效的仅mv解决方案进行比较,该解决方案(通常)总共仅创建2个进程。

    关于linux - 管道传输时,没有此类文件或目录。每个命令分别工作,但在管道传输时则不行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33114974/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com