ディレクトリを同じ名前のディレクトリに移動するには?

ディレクトリを同じ名前のディレクトリに移動するには?

複数のファイルを含むディレクトリがありますfoo

.
└── foo
    ├── a.txt
    └── b.txt

同じ名前のディレクトリに移動したい。

.
└── foo
    └── foo
        ├── a.txt
        └── b.txt

現在、一時ディレクトリを作成してbarから移動し、foo名前を次のようにbar変更しています。barfoo

mkdir bar
mv foo bar
mv bar foo

しかし、これは少し面倒な感じがし、barまだ使用されていない名前を選択する必要があります。

これを達成するためのよりエレガントで直接的な方法はありますか?それが重要な場合は、私はmacOSを使用しています。

答え1

名前がまだ使用されていない現在のディレクトリに一時ディレクトリを安全に作成するには、mktemp -d次のように使用できます。

tmpdir=$(mktemp -d "$PWD"/tmp.XXXXXXXX)   # using ./tmp.XXXXXXXX would work too

このmktemp -dコマンドは指定されたパスにディレクトリを作成し、Xパス名の末尾に-esが任意の英数字に置き換えられます。作成したディレクトリのパス名を返し、その値を1tmpdirに保存します。

tmpdirその後、すでに行ったのと同じプロセスを実行するときは、その変数を使用して次にbar置き換えることができます"$tmpdir"

mv foo "$tmpdir"
mv "$tmpdir" foo
unset tmpdir

最後に、unset tmpdir変数を削除することです。


1 一般的にしなければならないTMPDIR一時ファイルやディレクトリを作成するために使用したいディレクトリパスに環境変数を設定する機能がありますが、mktempmacOSのユーティリティは他のBSDシステムの同じユーティリティとは少し異なる動作をするように見え、まったく異なる場所にディレクトリを作成します。 。しかし、上記はmacOSで有効です。使い方がややtmpdir=$(TMPDIR=$PWD mktemp -d)簡単tmpdir=$(TMPDIR=. mktemp -d)質問macOSでは、デフォルトの一時ディレクトリが別のパーティションにあり、そのfooディレクトリに多くのデータが含まれている場合(つまり、速度が遅くなります)

答え2

macOSでは、renameHomebrewインストールコマンド(Perlスクリプト)を使用できます。

brew install rename

-p次に、(a la)を使用mkdirして必要なディレクトリを作成し、-Aプレフィックスを追加します。

% mkdir -p foo/bar; touch foo/{a,b}.txt foo/bar/c.txt
% rename -p -A foo/ foo/*
% tree foo
foo
└── foo
    ├── a.txt
    ├── b.txt
    └── bar
        └── c.txt

名前を変更せずに変更を表示するには、実行します-n(テストを実行):

% rename -p -A foo/ foo/* -n
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/bar' would be renamed to 'foo/foo/bar'

ビットファイルが存在する場合、simpleは*そのファイルを選択できません。別の方法を使用してくださいrename

  • Bashはドットファイルを一致させるためにGLOBIGNORE(間違って)使用します。*

    $ GLOBIGNORE=.; rename -p -A foo/ foo/* -n
    'foo/.baz' would be renamed to 'foo/foo/.baz'
    'foo/a.txt' would be renamed to 'foo/foo/a.txt'
    'foo/b.txt' would be renamed to 'foo/foo/b.txt'
    'foo/bar' would be renamed to 'foo/foo/bar'
    
  • findまたは、-print0次のようrenameに使用されます-0

    % find foo -mindepth 1 -maxdepth 1 -print0 | rename -0 -p -A foo/ -n
    Reading filenames from STDIN
    Splitting on NUL bytes
    'foo/b.txt' would be renamed to 'foo/foo/b.txt'
    'foo/a.txt' would be renamed to 'foo/foo/a.txt'
    'foo/bar' would be renamed to 'foo/foo/bar'
    'foo/.baz' would be renamed to 'foo/foo/.baz'
    

答え3

コンテンツが最大パラメータ制限を超えるのに十分でない限り(そして「許容可能な」エラーメッセージを気にしない限り)、以下より複雑である必要はありません。

mkdir foo/foo
mv foo/* foo/foo

隠しファイルの処理に対する修正:

mkdir foo/foo
mv foo/{.,}* foo/foo

答え4

あなたはすでにそれを知っています。現在の日付/時刻(ナノ秒単位)やPIDを複合サフィックスとして含むターゲット名など、一時ディレクトリに別の名前を選択できますが、まだディレクトリが存在しないとします。

dir=foo                         # The directory we want to nest
now=$(date +'%s_%N')            # Seconds and nanoseconds
mkdir "$dir.$now.$$"            # Create a transient directory
mv -f "$dir" "$dir.$now.$$/"    # Move our directory inside transient directory
mv -f "$dir.$now.$$" "$dir"     # Rename the transient directory to the name with which we started

保証された強力なソリューションが必要な場合は、mkdir成功するまで繰り返します。

now=$(date +'%s_%N')
while ! mkdir -m700 "$dir.$now.$$" 2>/dev/null
do
    sleep 0.$$
    now=$(date +'%s_%N')
done

関連情報