ディレクトリの下のすべてのディレクトリの前にアンダースコア文字を付けます。

ディレクトリの下のすべてのディレクトリの前にアンダースコア文字を付けます。

名前の先頭にアンダースコア「_」文字を含めるには、ディレクトリ内の複数のディレクトリの名前を変更する必要があります。

テストとして、コンテンツに3つのディレクトリを含む親ディレクトリを作成しました。

dir1, dir2 and dir3; three files: file1, file2, file3

3つのドットプレフィックスファイル:

.file1, .file2, .file3 

これまで、以下を使ってMacにインストールしてみましたgfindfindutils

gfind . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh

これにより、次のものが返されます。

mv: rename ./. to ./_.: Invalid argument

だから名前の変更と検索を試してみました。

find . -type d -exec rename 's/^/_/' {} \;

これにより、次のものが返されます。

Can't rename '.' to '_.': Invalid argument
Can't rename './dir1' to '_./dir1': No such file or directory
Can't rename './dir2' to '_./dir2': No such file or directory
Can't rename './dir3' to '_./dir3': No such file or directory

誰もが動作する解決策を持っているか、私が間違っている可能性がある部分を知っていますか?

答え1

私が正しく推測した場合は、次のファイルとディレクトリがあります。

$ mkdir dir{1,2,3} ; touch file{1,2,3} .file{1,2,3}
$ ls -A
.file1  .file2  .file3  dir1  dir2  dir3  file1  file2  file3

ディレクトリ名を_dir1、、_dir2に変更したいですか_dir3

それはfind/printf mv実現可能に見える。それが何を印刷するのか見てみましょう:

$ find . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n"
mv "./." "./_."
mv "./dir2" "./_dir2"
mv "./dir3" "./_dir3"
mv "./dir1" "./_dir1"

最初のコマンドは、「ドット」が特別で名前を変更できないため、エラーを発生させます。しかし、他のものは問題なく、必要に応じてディレクトリの名前を変更する必要があります。

$ find . -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh
mv: cannot move ‘./.’ to ‘./_.’: Device or resource busy
$ ls -d _dir*
_dir1  _dir2  _dir3

ただし、シェルにコマンドをパイプするのは少し見苦しく、ファイル名が十分に奇妙な場合、結果は驚くでしょう(たとえば、シェルで変数またはコマンドの置換をトリガーする$シンボルが含まれている場合)。

ファイルがすべて 1 つのレベルにある場合は、次のことを行う必要があります。

for x in * ; do [ -d "$x" ] && mv "$x" "_$x" ; done

_$x(すでに存在していても、$xその位置に移動されます。)

名前がドットで始まるディレクトリを含めるには、あらかじめ使用してくださいshopt -s dotglob

これも近いです:

find . -type d -exec rename 's/^/_/' {} \;

ただし、で始まるパスがfind提供されるため、これを考慮する必要があります。 1つのレベルでのみ機能します(先行をに変更)。rename./././_

find . -type d -exec rename 's,^./,./_,' {} \;

すべてのレベルのディレクトリを取得するには、find -execdirおそらく最も使いやすい方法です。ファイルディレクトリからコマンドを実行します。-depth名前の変更を正しい順序で処理する必要があります。

find . -depth -type d -execdir rename 's,^./,./_,' {} \;

たぶんそれも追加できます! -name .。例えば

$ mkdir foo foo/dir1 foo/dir2
$ find . -depth \! -name . -type d -execdir rename 's,^./,./_,' {} \;
$ ls  _foo
_dir1  _dir2

答え2

最初の試みの問題は、.すべてのサブディレクトリに加えて独自の名前(現在のディレクトリ)を変更しようとすることです。ただ渡ります。

gfind . -mindepth 1 -type d -name '*' -printf "mv \"%h/%f\" \"%h/_%f\"\n" | sh

しかし、実際にはしないでください。絶対にパイプに物を入れないでくださいshこれはうまくいきませんファイル名にシェル特殊文字が含まれていない場合。名前付きファイル(完全に有効ですが珍しいファイル名)がある場合、`rm -r ~`popはホームディレクトリに移動します。-exec以下のようにシェルを呼び出します。

_2番目の試みは、基本名の先頭、つまり最後に追加するのではなく、パス全体の先頭に挿入するため、機能しません/

find . -mindepth 1 -type d -exec rename 's![^/]+$!_$&!' {} \;

ネストされたディレクトリがある場合、それらのどれも実際には機能しません。findナビゲーション時にディレクトリ名が変更されるためです。これにより、この-depthオプションを使用してディレクトリ自体に対して作業を実行する前に、ディレクトリの内容に対して作業を実行する必要があります。

find . -mindepth 1 -depth -type d -exec rename 's![^/]+$!_$&!' {} \;

より便利には、シェルを呼び出してmv。これはすべてのPOSIXシステムに適用されます。

find . -depth -type d -name . -o -exec sh -c '
    for d do mv "$d" "${d%/*}/_${d##*/}"; done
' sh {} +

入れ子になったサブディレクトリがない場合は、単純なシェルループを使用できます。ドットで始まるディレクトリの名前を変更したくない場合は、ワイルドカードを使用してください。ワイルドカード*/は、ディレクトリとディレクトリへのシンボリックリンクのみを一致させます。

for d in */; do
  if [ "$d" = "*/* ] && [ ! -e "$d" ]; then continue; fi   # robustness in case there are no subdirectories
  if [ -L "$d" ]; then continue; fi     # optional: skip symbolic links to directories
  mv -- "$d" "_${d%/}"
done

名前がドットで始まるディレクトリを含むすべてのディレクトリの名前を変更するには、.*ワイルドカード文字も含めます。

for d in .*/ */; do
  if [ "$d" = "*/* ] && [ ! -e "$d" ]; then continue; fi
  if [ -L "$d" ]; then continue; fi
  mv -- "$d" "_${d%/}"
done

fooに移動するという_fooディレクトリがすでに存在する場合、以前のディレクトリはに_foo移動されます。これを防ぐには、明示的なテストを追加してください。foo_foo/foo

あるいは、zshを使用することもできます。 macOSにはプリインストールされています。初めて実行してautoload -U zmv(あなたのスクリプトに入れて.zshrc)ロードしてください。zmv機能、非再帰バージョン(シンボリックリンクを除くドットファイルを含む)は、次  (/D)のセットです。グローバル予選):

zmv -Q '*(/D)' '_$f'

または再帰バージョン(使用修飾子ディレクトリ名とデフォルト名の抽出:

zmv -Q '**/*(/D)' '$f:h/_$f:t'

zmv宛先がすでに存在する場合、ジョブは拒否されます。

関連情報