将所有目录下大写


Answers:


10

所有目录都位于一个级别,还是递归?

sh

一方面:

autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'

递归地:

zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'

说明:zmv根据给定的替换文本重命名与模式匹配的文件。-o-i-i选项传递给幕后的每个mv命令(请参见下文)。在替换的文本,$1$2,等等,都是在图案中的连续带括号的组。**递归地表示所有(子)*目录。最后(/)的不是带括号的组,而是全局限定符,意为仅匹配目录。${2:l}转换$2为小写。

随身携带

一方面:

for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done

最终/将匹配内容限制为目录,并mv -i在发生冲突时要求其进行确认。-i如果发生冲突,请删除进行覆盖,然后使用yes n | for …。不会被提示,也不会执行任何可能会发生冲突的重命名。

递归地:

find root/* -depth -type d -exec sh -c '
    t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
    [ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;

使用-depth确保深度嵌套目录在其祖先之前得到处理。名称处理取决于是否存在/; 如果要在当前目录中调用operate,请使用./*(使shell脚本适应.或应付*读者的练习)。

Perl重命名

在这里,我使用Debian和Ubuntu附带的Perl重命名脚本/usr/bin/prename(也通常可用rename)。一方面:

rename 's!/([^/]*/?)$!\L/$1!' root/*/

递归地使用bash≥4或zsh:

shopt -s globstar  # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/

递归地,可移植地:

find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +

至少在OS X上,如果任何目录都已经小写,则将失败:mv -i a a给出“ mv:将a重命名为a / a:无效的参数”。
Janus

@Janus:是的,您会收到一条错误消息,该消息很难看(尽管在命令行中无害)。但是无论如何,我应该使用zmv,它可以处理这种情况。
吉尔(Gilles)“所以,别再邪恶了”,

然后-execdir,我发现其中的一个很棒:unix.stackexchange.com/questions/5412/…然后,我发现它有些PATH疯狂并且令人难过:-(
Ciro Santilli新疆改造中心法轮功六四事件

4

没有一个命令可以执行此操作,但是您可以执行以下操作:

for fd in */; do
  #get lower case version
  fd_lower=$(printf %s "$fd" | tr A-Z a-z)
  #if it wasn't already lowercase, move it.
  [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done

如果需要强大的功能,则应该考虑已经存在两个仅大小写不同的目录的情况。

作为单线:

for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done

这在我的写作(基本上相同)的建议中途出现:for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
frabjous 2011年

我正在尝试解决问题find -type d,但未能完全解决
Michael Mrozek

1
我的本能是这样做的for fd in */;,因此避免了检查它是否是目录的需要,但是我不知道这种本能是否很好。
史蒂文D

是的,因为... * /会更好。
肖恩·高夫

1
@Shawn:tr已经预计范围,因此tr '[A-Z]' '[a-z]'转换[[]]一笔带过。这是无用但无害的。但是,如果在当前目录中有一个文件名带有一个大写字母的文件,那么外壳程序将不带引号将其括起来。
吉尔(Gilles)“所以,别再邪恶了”,

0

我将此视为一个单线挑战:)首先,建立一个测试案例:

$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar     aBar.txt    aeVe.txt    afoo.txt    eVe     foo

find经常用大写字母识别目录,然后通过来将它们小写。猜猜使用有点乱,但是当我尝试直接转义时,我的头总是爆炸。sh -c 'mv {} echo {} | tr [:upper:] [:lower:]'sh -cfind

$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt    aeVe.txt    afoo.txt    bar     eve     foo

请注意:此解决方案不检查外壳是否会导致碰撞!


检查碰撞很容易:mv -i。更大的问题是您没有使用正确的引号,因此,如果\[*?名称中的任何地方有特殊字符(空格或),则命令将失败。find除非递归使用,否则没有意义,然后您需要find -depth-path必须是-name。请参阅我的答案以获取工作示例。
吉尔(Gilles)“所以,别再邪恶了”,

@吉尔斯 谢谢!mv -i写完这本书后,我看到了你。用引号的要点...
Janus

0

find -execdir| 改名

如果不是因为相对路径疯狂,这将是最好的方法,因为它避免了Perl regex fu仅对基本名称起作用:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;

-execdir首先cd进入目录,然后仅对基本名称执行。

不幸的是,如果您在...中有相对路径,我将无法摆脱该PATH黑客行为,并且find -execdir拒绝执行任何操作PATHhttps : //askubuntu.com/questions/621132/why-using-the-execdir-action-目录路径不安全/ 1109378#1109378

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.