ディレクトリの下のすべてのディレクトリを下げる


回答:


10

1つのレベルのすべてのディレクトリ、または再帰的に?

Zsh

1つのレベルで:

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

再帰的に:

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

説明:zmv指定された置換テキストに従って、パターンに一致するファイルの名前を変更します。-o-i内部の-imvコマンドにオプションを渡します(以下を参照)。置換テキストでは、$1$2、など、パターン中の連続括弧基です。**すべての(サブ)*ディレクトリを再帰的に意味します。final (/)は括弧で囲まれたグループではなく、ディレクトリのみに一致することを意味するglob修飾子です。小文字に${2:l}変換$2します。

ポータブル

1つのレベルで:

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すると、深くネストされたディレクトリが祖先の前に処理されます。名前の処理は/、現在のディレクトリで操作を呼び出したい場合は、./*(シェルスクリプトを適応させる.*、読者の演習として残しておきます)を使用します。

Perlの名前変更

ここでは、DebianおよびUbuntuに同梱されているPerlの名前変更スクリプトを使用し/usr/bin/prenameます(通常も利用可能ですrename)。1つのレベルで:

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:無効な引数」に指定します。
ヤヌス

@Janus:そうです、エラーメッセージが表示されますが、これはいです(ただし、コマンドラインでは無害です)。しかし、とにかくzmvを使用するべきでした。zmvはこのケースを処理します。
ジル「SO-悪であるのをやめる」

私はその後、約見つかっ-execdir素晴らしいである:unix.stackexchange.com/questions/5412/...私は、それはいくつか持っていることがわかったPATH狂気をして:-(悲しかった
チロSantilli新疆改造中心法轮功六四事件

4

それを行うコマンドは1つではありませんが、次のようなことができます。

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

堅牢にする必要がある場合は、大文字と小文字が異なるだけの2つのディレクトリが既に存在する場合を考慮する必要があります。

ワンライナーとして:

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
狂気

私はでそれを解決しようとしていたがfind -type d、それを得ることができませんでした
マイケルMrozek

1
私の本能はfor fd in */;そうすることでしたので、それがディレクトリであるかどうかのチェックの必要性を回避しますが、この本能が良いものであるかどうかはわかりません。
スティーブンD

ええ、... * /の方が良いでしょう。
ショーンJ.ゴフ

1
@Shawn:trすでに範囲を期待しているので、とにtr '[A-Z]' '[a-z]'変換[します。これは無意味ですが、無害です。ただし、引用符なしでは、現在のディレクトリに1文字の大文字の名前のファイルがある場合、シェルは括弧を展開します。[]]
ジル 'SO-悪である停止

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。そして、必要であり、そうでなければなりません。実例については私の答えをご覧ください。
ジル 'SO-悪である停止

@Giles。ありがとう!mv -iこれを書いてからあなたを見ました。引用の良い点
...-ヤヌス

0

find -execdir| リネーム

これは、Perlの正規表現fuがベース名にのみ作用することを回避するため、相対パスの狂気のためでなければ、それを行うための最良の方法でしょう。

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

-execdir 最初 cdベース名でのみ実行する前に、ディレクトリに移動します。

残念ながら、私はそれを取り除くことができないPATHハッキング一部、find -execdirあなたが相対パスを持っている場合は何もすることを拒否PATH...:/ubuntu/621132/why-using-the-execdir-action-パスに対して安全でないディレクトリに対して11/1197#1109378

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.