在OSX终端中,我尝试压缩文件夹层次结构,但由于里面的文件名称相同,我想用以前的文件夹名称扩展文件名:
我想从这里开始:
/dirA1/dirB1/file1.ext
/dirA1/dirB2/file1.ext
...
/dirA2/dirB1/file1.ext
...
到
/file1-dirA1-dirB1.ext
/file1-dirA1-dirB2.ext
...
/file1-dirA2-dirB1.ext
...
我尝试将重命名(Batch renaming files in OSX terminal)与展平(https://unix.stackexchange.com/questions/52814)结合起来,但没有运气......
我会从“发现”开始吗?但是如何将目录名称传递给“mv”?
非常感谢你!
答案 0 :(得分:0)
一种安全但不是很快的方法是将B
与find
一起使用,将每个文件传递给执行替换的shell命令,如下所示:
-exec
(cd /path; find . -type f -exec sh -c 'newname=${1:2}; filename=${newname##*/}; dirname=${newname%/*}; newname=$filename-${dirname//\//-}; echo mv "$1" "$newname"' -- {} \;)
而不是cd /path
的原因是我们可以使用该基本目录中的相对路径,这样可以更轻松地创建拼合文件名。
对元素的更多解释:
find /path
执行-exec sh -c '...' -- {}
,运行sh
中指定的命令。 -c '...'
是{}
找到的路径。 find
语法是将参数作为位置参数传递给脚本,可通过-- ...
,$1
访问,等等。$2
获取newname=${1:2}
,第一个位置参数,并从中提取子字符串,跳过前两个字符。我这样做是因为$1
的输出将包含以find .
开头的路径,我们希望在用./
替换/
之前将其删除。-
提取路径的文件名部分,删除从开头到最后filename=${newname##*/}
的所有内容/
提取路径的目录名称部分,删除最后一个dirname=${newname%/*}
及其后的所有内容/
将所有${dirname//\//-}
替换为/
。如果您要删除-
而不是替换,则可以编写/
这种技术是安全的,因为它可以与文件名中的任何特殊字符一起使用。它很慢,因为它为每个文件运行${dirname//\//}
。
在此步骤之后,原始文件的空目录将保留,您可能想要删除它们:
sh
答案 1 :(得分:0)
通过将sh
输出提供给find … -print0
循环,您可以安全地处理此问题而不对每个文件执行while read
,例如:
while IFS= read -r -d '' old; do # read filenames into $old
# -d '' : read until \0
# -r : no backslash escapes
# IFS= : no trimming whitespace
if [[ $old =~ (.*)/(.*)\.(.*) ]]; then # regex with capture groups:
# 1 2 3
set -- "${BASH_REMATCH[@]}"
mv "$old" "${2}-${1//\/}.${3}"
fi
done < <(find . -type f -print 0)
上面set -- "${BASH_REMATCH[@]}"
的目的只是将包含正则表达式匹配组的数组成员移动到位置参数($1
,$2
等)中易读性。