我正在尝试仅针对某些文件类型(.mkv、.mp4、.avi)执行目录中下划线的查找和替换。这是我正在使用的代码(我使用的是 Mac OS X 10.9):
find . \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' \) -print0 |
xargs -0 sed -i '' -e 's/\./_/g'
我阅读了两种解决方案,但都不起作用。
我首先将以下内容添加到我的 ~/.bash_profile 中:
export LC_CTYPE=C
export LANG=C
这导致了同样的错误,所以我尝试使用:
LC_ALL=C sed ...
这不起作用,我收到此错误:
xargs: LC_ALL=C: No such file or directory
还有其他建议吗?我对 shell 很陌生。
编辑:这就是我想要实现的目标:
我正在尝试遍历目录并将文件名中的下划线替换为点。
例子:
random_movie.mp4 应该是 random.movie.mp4
答案1
你应该-exec
在这里使用:
find . \( -name '*.mp4' -o -name '*.mkv' -o -name '*.avi' \) \
-exec sh -cf 'IFS=._
for f do d=${f%/*} f=${f##*/}
[ -n "${f##*_*}" ] && continue
set -- $f
printf "%s\n" "mv \\" "$d/$f \\" "$d/$*"
done' find.rename.shc {} +
正如所写的,这只会打印您执行该命令时它将执行的命令。例如,在我的.../media/Videos
目录上运行上述命令会打印以下一些内容:
mv \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure_Time.s05e37.The_Box_Prince.mp4 \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure.Time.s05e37.The.Box.Prince.mp4
mv \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure_Time.s05e38.Red_Starved.mp4 \
/mnt/bcache/media/Videos/TV/Adventure_Time/Adventure.Time.s05e38.Red.Starved.mp4
为了完成它,你需要改变:
...
set -- $f
printf "%s\n" "mv \\" "$d/$f \\" "$d/$*"
...
...只是...
...
set -- $f; mv "$d/$f" "$d/$*"
...
一般来说,您应该避免通过管道传递文件名和类似文件,因为当您这样做时,您会丢失文件名的头部和尾部的分隔符 - 它不再是一个参数,而是变成流中的字节序列。该-exec
选项find
使您能够在正在运行的进程的子进程中保留这些分隔符find
。它+
的作用类似于xargs
- 仅在必要时执行指定的子进程以避免出现某种ARGMAX
情况。
关于这个sed
问题 - 你可以尝试:
LC_ALL=C xargs sed ...
这至少应该避免xargs
将环境变量声明解释为参数。但它不会帮助您编辑任何文件名。
最后一点 - 您提到的问题通常是由模式空间中出现的不完整的多字节序列引起的。 POSIX 指定.
无法匹配部分一个字符 - 因此.*
在该上下文中失去了它的意义。强制C
区域设置应该可以解决这个问题 - 但使用 GNU 清除保留/模式空间的另一个选项sed
是z
命令。