我只能访问 busybox。
我有一个文件夹,像这样:
prueba/$: ls
./uno
./dos
./tres
每两个子目录(uno、dos)都有许多文件(名称中带有空格和非 ASCII 字符),我想将它们移动到另一个子目录(tres)。
所以我这样做了(转义字符只是因为,确保我在复制和使用 yes 时不会做冗余,只是为了替换目录 [tres] 中已有的任何文件,我之前遇到过 mv -f 问题):
prueba/$: busybox find . -type f -not \( -path . -o -path ./tres \) -exec sh -c ' yes | mv "$1" ./tres ' sh {} \+
但它只移动它找到的第一个文件,然后退出。
但如果我跑:
prueba/$: busybox find . -type f -not \( -path . -o -path ./tres \) -exec sh -c ' yes | mv "$1" ./tres ' sh {} \;
我得到了我所期望的。所有文件都从子目录“uno”和“dos”移动到子目录“tres”。
;
当【隐式循环】和+
【隐式批处理】到位时,激活的内部机制是什么?
第一个命令行(带有+
)有什么问题?
以下是不可能的:
mv -f ./uno/* ./dos/* ./tres/
我正在做一些自动化工作,需要我只运行一行代码并完成工作。另外,这是一个无聊的解决方案。
编辑:
背后的原因find . -exec sh -c 'CMD "$1"' sh {} \;
答案1
将其更改为:
find uno/ dos/ -type f -exec sh -c 'exec mv -f "$@" tres/' sh {} +
您的代码存在的问题:
find . -not -path ./tres
确实排除./tres
,但不排除./tres/any-file-in-it
-exec sh 'mv "$1" tres' sh {} +
sh
使用尽可能多的文件作为参数进行调用,但您只移动第一个 ($1
)。"$@"
扩展到全部位置参数作为单独的参数,就像您编写的一样。"$1" "$2" "$3" ... "$last"
- 注意
!
作为标准替代非标准-not
- 请注意,这
+
在任何 shell 中都不是特殊字符。不需要引用它。 - 请注意
-f
选项mv
以避免首先提示,这样您就不需要yes
。如果您仍然想使用yes
,您可以这样做yes | find ... -exec sh -c 'exec mv ...
,assh
和mv
will 继承find
stdin 并y
从那里读取 s。 - 通过
mv
GNU coreutils 和最新版本的实现busybox
,您可以sh
使用 来避免调用find ... -exec mv -ft tres {} +
。
如果您想从任何目录(递归地)移动文件,除了当前目录中的文件./tres
和排除当前目录中的文件外,您需要:
LC_ALL=C find . -path ./tres -prune -o \
-path './*/*' -type f -exec sh -c 'exec mv -f "$@" tres/' sh {} +
上面的内容-prune
告诉find
不要在 中查找文件./tres
,而对于其他文件(与so-path './*/*'
相结合,匹配任何字节字符串,而不仅仅是字符)限制为路径在前导 后至少包含一个的文件,因此排除 中的文件当前目录。LC_ALL=C
*
/
./
和zsh
:
set -o extendedglob # best in ~/.zshrc
mv -f -- (^tres)/**/*(D.) tres/
但请注意,如果当前目录中存在指向目录的符号链接,则会遵循它们。如果达到系统对参数数量和大小的限制,它也可能会失败(请参阅zargs
解决该问题)。
与 相反find
,zsh
glob 会对文件列表进行排序,因此,如果有多个同名文件,则最终出现的文件./tres
将更具确定性(这将是路径排在最后的文件,但请注意,因为顺序uno
排在最后)dos
是词汇的;所有其他的都会丢失)
1 您可以添加n
glob 限定符来获取数字顺序,但这仅适用于数字序列(例如,dir2
在之前dir10
),uno
仍会在之后排序dos
)