我有这样的目录结构:
/root/1232/medium
/root/1234/medium
/root/1245/medium
/root/1253/medium
/root/1263/medium ...
在这些文件夹中的每一个1232,1234,1245 ...我有我想要移动到他们的媒体子目录的文件。这意味着/ root / 1232 /中的所有文件都应该移动到/ root / 1232 / medium,并且/ root / 1234 /中的所有文件都应该移动到/ root / 1234 / medium。 我尝试了各种各样的查找版本,但没有一个能够工作。 问题是我有超过15000个文件夹,否则我会手动移动它。 感谢。
答案 0 :(得分:1)
如果您使用的是最新版本的bash(即,年龄不超过10年),您可以通过发出以下命令启用扩展通配:
shopt -s extglob
在许多其他有用的功能中,扩展的globbing允许你通过调用!(pattern)
因此,要解决您的问题,您可能会执行类似
的操作for folder in /root/12* ; do
mv $folder/!(medium) $folder/medium/
done
将迭代匹配模式/root/12*
的所有文件夹(或任何其他项目),然后对于每个文件夹,只要未调用medium
,它们就会尝试移动所有内容。到那里实际上称为medium
的目录。那是关于它的:)
有关负/反向通配的详细信息,另请参阅this SO question。
如果出于某种原因你不想启用扩展通配(或者你的bash不支持它),你可以做一些反向grepping:
for basefolder in /root/12* ; do
for entry in $(ls $basefolder | grep -v medium) ; do
mv $basefolder/$entry $basefolder/medium
done
done
答案 1 :(得分:0)
命令:
find /root/* -mindepth 1 -maxdepth 1 -type f
在-type f
的子目录中查找深度为1(-mindepth 1 -maxdepth 1
)的所有文件(/root
)。 -mindepth
参数强制find
跳过/root
(它们深度为0
)的文件,否则将会找到这些文件。
运行上面的命令并验证它是否生成了您要移动的文件列表,而不是其他任何内容。您可以使其更严格,以确保它不返回您不想移动的文件。例如,如果您知道要处理的/root
的所有子目录都以12
开头,那么您可以使用find /root/12* ...
。
如果您确定拥有生成正确文件列表的命令,请将其嵌入for
命令,如下所示:
IFS=$'\n'
for i in $(find /root/* -mindepth 1 -maxdepth 1 -type f); do
mv "$i" "${i%/*}/medium/"
done
只是为了确保它不会破坏任何内容,将echo
放在mv
前面并运行它以查看它将执行的操作。如果一切正常,请删除echo
并享受。
确保使用bash
运行上述命令。 $()
构造是特定于bash的;其他炮弹可能会或可能不会理解它,或者它们可能以不同的方式解释它。表达相同行为的更便携方式是使用反引号(``
)而不是$()
。
命令替换运算符($()
或``
)运行它包含的命令并捕获其输出。 find
命令的输出是要移动的文件列表。
由$()
生成的字符串然后由for
迭代;在每次迭代中,环境变量i
设置为find
输出的一行。 find
输出的每一行都包含我们要移动的一个文件的路径。
在IFS
块之前将$'\n'
环境变量设置为for
可确保find
的输出仅在换行符上拆分。 IFS
的默认值(“内部字段分隔符”)为<space><tab><newline>
如果找到具有空格的文件,则for
命令会错误地将find
的输出拆分为IFS=$'\n'
在他们的名字。
如果您完全确定要移动的文件名称中没有空格,则可以删除mv
行。
接下来,在每次迭代中,构建并执行${i%/*}
命令行。 i
参数展开会从%
的值中删除与/*
模式匹配的最短右边(${i%/*}/medium/
)。删除的部分是文件名和完整文件路径中的斜杠。
medium/
基本上用mv "$i" "$(dirname $i)/medium/"
替换文件名。另一种可能的方法是:
dirname
它使用命令$i
仅从${i%/*}
中提取目录(删除文件名)。
第一种方式(git log -- myFile
)是首选,因为它更快。