Macos 将所有文件从子目录移动到新目录,而不覆盖
我想合并到多个子目录中的1个目录文件中 除了在扩展名之后添加随机字符串外,下面的内容非常接近;我想在分机前得到:Macos 将所有文件从子目录移动到新目录,而不覆盖,macos,bash,random,rename,mv,Macos,Bash,Random,Rename,Mv,我想合并到多个子目录中的1个目录文件中 除了在扩展名之后添加随机字符串外,下面的内容非常接近;我想在分机前得到: find . -type f -iname "[a-z,0-9]*" -exec bash -c 'mv -v "$0" "./$( mktemp "$( basename "$0" ).XXX" )"' '{}' \; 我搜索了几十篇其他帖子,但都没有提到我的具体情况: 我在OSX上(所以它是Bash的BSD风格;例如,mv没有-t选项) 许多文件都有相同的名称,因此我需要在m
find . -type f -iname "[a-z,0-9]*" -exec bash -c 'mv -v "$0" "./$( mktemp "$( basename "$0" ).XXX" )"' '{}' \;
我搜索了几十篇其他帖子,但都没有提到我的具体情况:
- 我在OSX上(所以它是Bash的BSD风格;例如,mv没有-t选项)
- 许多文件都有相同的名称,因此我需要在mv期间重写它们(我不能只为mv使用-n选项,因为太多的文件将无法移动)
- 这些文件的种类不尽相同,因此我需要使用
find-typef
- 我想排除.DS_存储文件,因此一个不错的选择似乎是
find-typef-iname“[a-z,0-9]*”
- 我希望重写文件的名称采用:oldname-random_string.xyz的形式(但我也可以将文件重命名为顺序列表:00001.xyz、00002.xyz等)
- 这些文件从我的主目录向下隐藏了4层:
- 主/主任
- 目录2
- 目录3
- 目录4
- 目录5
- 文件
- 为了简单起见,与.sh脚本相比,我更喜欢bash命令(但两者我都喜欢)
mktemp
提供了一个模板,以便XXX
模式正好出现在后缀之前。使用GNUsed
:
find-输入f-iname“[a-z,0-9]*”-exec bash-c'mv-v“$1”。/$(mktemp-u“$(basename“$1”| sed-E-E'\'s/\。([^.]+)$/.XXX.\1/''''-E'\''/'/'./'/'$/.XXX/'''.''''.'''''.'''''''''.'''.''.'''.''/'''.'''''''''''''';
上面的关键添加是使用sed
在文件名后缀前插入XXX
:
sed -E -e 's/\.([^.]+)$/.XXX.\1/' -e '/XXX/ !s/$/.XXX/'
这有两个命令。第一个将.XXX
放在扩展名之前。仅当文件名没有扩展名时才运行第二个命令,在这种情况下,它会将.XXX
添加到文件名的末尾
在第一个命令中,源正则表达式由两部分组成。第一个是\.
,它匹配一个句点。第二个是([^.]+)$
,它将扩展捕获到组1中。替换将其替换为.XXX.\1
,其中\1
是组1的sed
符号,在本例中,组1是文件的扩展名
OSX溶液
在OSX下,mktemp
没有用处,因为它只支持带有XXX部件尾随的模板。作为一种解决方法,我们可以使用bash脚本生成非重叠文件名:
#!/bin/bash
find . -type f -iname "[a-z,0-9]*" -print0 |
while IFS= read -r -d '' fname
do
new=$(basename "$fname")
[ "$fname" = "./$new" ] && continue
[ "$new" = .DS_store ] && continue
name=${new%.*}
ext=${new#"$name"}
n=0
new=$(printf '%s.%03i%s' "$name" "$n" "$ext")
while [ -f "$new" ]
do
n=$(($n + 1))
new=$(printf '%s.%03i%s' "$name" "$n" "$ext")
done
mv -v "$fname" "$new"
done
上面使用find
命令获取文件名。选项-print0
用于确保它可以处理较难的文件名。while
循环将这些文件名逐个读取到变量fname
中fname
包含源文件的完整路径。然后,不带路径的文件名存储在new
中。然后进行两次检查。如果源文件已在当前目录中,脚本将继续执行下一个循环。类似地,如果文件名id.DS\u Store
,也将跳过它。(给定的find
命令已经跳过这些文件。这一行只是为了将来的灵活性。)接下来,文件名分为两部分:name
和ext
,扩展名<代码>分机包括前置期间。接下来,循环检查格式为name.NNN.ext的文件,并在第一个尚不存在的文件处停止。源文件将移动到该名称的文件中
关于GNU解决方案及其兼容性的相关说明
- 在上面的GNU命令中引用是复杂的。
的参数需要用单引号引起来,以防止调用bash执行过早的变量替换。此外,bash子shell执行bash-c
命令时需要使用单引号,以防止历史扩展干扰否定的使用,sed
,在
命令中sed
- OSX(BSD)
不支持将命令与分号组合在一起。因此,每个命令都通过一个单独的sed
选项提供给-e
sed
- OSX(BSD)
似乎对待sed
与GNU+
有所不同。当使用sed
(扩展正则表达式)选项时,这种不兼容性似乎消失了。(相应的GNU选项是-E
,但作为一种未记录的兼容性功能,GNU-r
也支持sed
-E
mv-v“$1”。/$(mktemp-u“$(basename“$1”| sed”s/\.\([^.]\+\)$/.XXX.\1/;/XXX/!s/$/.XXX/”))mktemp-u“$(basename“$1”| sed”s/\.\([^.]\+\)$/.XXX.\1/;/XXX/!s/$/.XXX/”“basename“$1”| sed”s/\.\([^.]\+\)$/.XXX./A/001.jpg->/001.jpg.qzH
下面是运行sed echo时的结果