ディレクトリ内のすべてのファイル(非表示のものを含む)を別のディレクトリに移動するにはどうすればよいですか?
たとえば、「。hidden」と「notHidden」というファイルが入った「Foo」というフォルダがある場合、両方のファイルを「Bar」という名前のディレクトリに移動するにはどうすればよいですか? 「.hidden」ファイルが「Foo」に残っているため、以下は機能しません。
mv Foo/* Bar/
自分で試してみてください。
mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/
mv Foo/*(DN) Bar/
または
setopt -s glob_dots
mv Foo/*(N) Bar/
(ディレクトリが空でないことがわかっている場合は、(N)
を省略してください。)
shopt -s dotglob nullglob
mv Foo/* Bar/
ディレクトリが空でないことがわかっている場合:
FIGNORE='.?(.)'
mv Foo/* Bar/
for x in Foo/* Foo/.[!.]* Foo/..?*; do
if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done
mv
コマンドが成功した場合でもエラーステータスを返すようにしたい場合は、はるかに簡単です。
mv Foo/* Foo/.[!.]* Foo/..?* Bar/
find Foo/ -mindepth 1 -maxdepth 1 -exec mv -t Bar/ -- {} +
ソースディレクトリに変更してもかまわない場合:
cd Foo/ &&
find . -name . -o -exec sh -c 'mv -- "$@" "$0"' ../Bar/ {} + -type d -Prune
ここでは、bash、ksh93、zshでドットファイルを照合するかどうかを制御する方法について詳しく説明します。
dotglob
オプション を設定します。
$ echo *
none zero
$ shopt -s dotglob
$ echo *
..two .one none zero
より柔軟な GLOBIGNORE
variable もあり、無視するワイルドカードパターンをコロンで区切ったリストに設定できます。設定されていない場合(デフォルト設定)、シェルは、dotglob
が設定されている場合は値が空であるかのように動作し、オプションが設定されていない場合は値が.*
であるかのように動作します。マニュアルの Filename Expansion を参照してください。 .
がパターンによって明示的に一致しない限り、普及ディレクトリ..
および.
は常に省略されます。
$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one
FIGNORE
variable を設定します。設定されていない場合(デフォルト設定)、シェルは値が.*
であるかのように動作します。 .
と..
を無視するには、それらを明示的に一致させる必要があります(ksh 93s + 2008-01-31のマニュアルでは、.
と..
は常に無視されると記載されていますが、実際の動作は正しく説明されていません)。
$ echo *
none zero
$ FIGNORE='@(.|..)'
$ echo *
..two .one none zero
$ FIGNORE='n*'
$ echo *
. .. ..two .one zero
ドットファイルを パターン に含めるには、それらを明示的に一致させます。
$ unset FIGNORE
$ echo @(*|.[^.]*|..?*)
..two .one none zero
ディレクトリが空の場合に展開を空にするには、N
パターンマッチングオプション~(N)@(*|.[^.]*|..?*)
または~(N:*|.[^.]*|..?*)
を使用します。
dot_glob
オプション を設定します。
% echo *
none zero
% setopt dot_glob
% echo *
..two .one none zero
パターンが先頭の.
に明示的に一致する場合でも、..
と.
は決して一致しません。
% echo .*
..two .one
D
glob qualifier を使用すると、ドットファイルを特定のパターンで含めることができます。
% echo *(D)
..two .one none zero
N
グロブ修飾子を追加して、展開が空のディレクトリ*(DN)
に空になるようにします。
注:.one
、..two
、およびnone
変数の設定に基づいて、ファイル名の展開結果が異なる順序で取得される場合があります(例:LANG
の後にLC_COLLATE
の後にLC_ALL
)。
#!/bin/bash
shopt -s dotglob
mv Foo/* Bar/
man bash
からdotglob設定されている場合、bashには「。」で始まるファイル名が含まれます。パス名展開の結果。
bash
でこれを行う簡単な方法は、
_mv {Foo/*,Foo/.*} Bar/
_
ただし、これによりディレクトリも移動します。
非表示を含むすべてのファイルを移動したいが、ディレクトリは移動したくない場合は、forループとテストを使用できます。
for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;
1つの方法は、find
を使用することです。
find Foo/ -type f -exec mv -t Bar/ {} \+
-type f
findコマンドをファイルの検索に制限します。 -type
、-maxdepth
、-mindepth
find
のオプションを使用して、サブディレクトリを考慮してコマンドをカスタマイズします。 Findは非常に長くて便利です manual page 。
コピーコマンドcp
を試してください:
$ cp -r myfolder/* destinationfolder
cp -r
は再帰的にコピーすることを意味するため、すべてのフォルダーとファイルがコピーされます。
削除コマンドrm
を使用して、フォルダーを削除できます。
$ rm -r myfolder
minimalLinuxディストリビューションの場合、以下が機能するはずです。まず、すべての基本的な移動を実行します(これにより、隠しファイルが失われます)。次に、すべての隠しファイル(.
および..
を含むnotが実際に移動されます)を移動します。
mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null
注:目に見えるコンテンツがない場合、最初のコマンドはエラーメッセージを生成します。 2番目のコマンドはalwaysは、.
および..
を移動できないことを示すエラーを生成します。そのため、エラーを/dev/null
にパイプするだけです(図のように)。
これをワンライナーとして必要な場合は、セミコロンで結合するだけです。
mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
Rsyncは別のオプションです。
rsync -axvP --remove-source-files sourcedirectory/ targetdirectory
これが機能するのは、rsyncでは末尾のスラッシュが重要であるため、sourcedirectory/
はディレクトリのコンテンツを参照し、sourcedirectory
はディレクトリ自体を参照するためです。
この方法の欠点は、rsyncがディレクトリではなく、移動後にのみファイルをクリーンアップすることです。したがって、空のsourcedirectoryツリーが残ります。その回避策については、以下を参照してください。
したがって、これは移動操作には最適ではないかもしれませんが、コピー操作には非常に役立ちます。
bash/fishの回答
ワイルドカードを使用してこれを行う方法は次のとおりです。
.[!.]* ..?*
は一致しますすべての隠しファイル.
および..
以外
.[!.]* ..?* *
は一致しますすべてのファイル(非表示または非表示).
および..
を除く=
この質問の特定の例に答えるには、cd foo && mv .[!.]* ..?* * ../bar
が必要です
説明
.[!.]*
は、1つのドットで始まり、その後にドット以外の任意の文字が続くファイル名に一致しますオプションで任意の文字列が続きます。これは十分に近いですが、..foo
のような2つのドットで始まるファイルがありません。そのようなファイルを含めるには、2つのドットで始まり任意の文字が続くファイル名に一致する..?*
を追加し、オプションで後に任意の文字列を続けます。
テスト
以下のコマンドでこれらのワイルドカードをテストできます。私はbashとfishの下でそれらをうまく試しました。 sh、zsh、xonshでは失敗します。
mkdir temp
cd temp
touch a .b .bc ..c ..cd ...d ...de
ls .[!.]* ..?*
# you get this output:
.b .bc ..c ..cd ...d ...de
# cleanup
cd ..
rm -rf temp
これはbashでうまく機能し、シェルオプションを変更する必要がないことがわかります
mv sourcedir/{*,.[^.]*} destdir/
編集:
したがって、G-manが述べたように、私の元の回答はposixに準拠しておらず、上記のndemouの回答とほぼ同じですが、1つの変更点があります。これは、ソースディレクトリにcd
する必要がないことを意味します。それほど大きな変化ではありませんが、それは異なります。
例:次のレイアウトがすでにあるとします。
$ tree -a
.
├── destdir
└── sourcedir
├── ..d1
├── ..d2
├── ..double
├── file-1
├── file-2
├── .hidden-1
├── .hidden-2
├── ...t1
└── ...t2
元の質問では、ピリオドが1つしかない隠しファイルしか触れていませんでしたが、名前の先頭に2つ以上のピリオドがあるものがあるとします。中かっこに式を追加するだけです。次に実行できます
mv sourcedir/{*,.[!.]*,..?*} destdir/
これは次のように拡張されます。
mv sourcedir/file-1 sourcedir/file-2 sourcedir/.hidden-1 sourcedir/.hidden-2 sourcedir/..d1 sourcedir/..d2 sourcedir/..double sourcedir/...t1 sourcedir/...t2 destdir/
destdirにあるすべてのファイルが表示されます。
$ tree -a
.
├── destdir
│ ├── ..d1
│ ├── ..d2
│ ├── ..double
│ ├── file-1
│ ├── file-2
│ ├── .hidden-1
│ ├── .hidden-2
│ ├── ...t1
│ └── ...t2
└── sourcedir
4.xでさらに追加すると、bashで中かっこを使用してかなりクールなことができます。 bash-hackers をチェックして、気の利いた例をいくつか見てください。
Moveコマンドのファイルを選択するために、バッククォートを使用してgrepを実行できる場合もあります。それらをmvに渡します。
つまり隠しファイルの場合
find Foo -maxdepth 1 | egrep '^Foo/[.]' # Output: .hidden
そう
mv `find Foo -maxdepth 1 | egrep '^Foo/[.]'` Bar # mv Foo/.hidden Bar
選択した隠しファイルのみをBar
に移動します:
mv `find Foo -maxdepth 1 | egrep '^Foo/.'` Bar # mv Foo/.hidden Foo/notHidden Bar
「。」以降のFoo内のすべてのファイルをBarに移動します。 egrepコマンドでは、角括弧なしのワイルドカードとして機能します。
^
文字は、一致が行の先頭から始まることを保証します。
egrep
パターンマッチングの詳細については、 here を参照してください。
maxdepth 1
を使用すると、サブディレクトリに移動することができなくなります。
ファイルをコピーせずに...
rsync -ax --link-dest=../Foo/ Foo/ Bar
警告:
--link-dest
パスは、DESTINATIONに対する絶対パスまたは相対パスである必要があります(例ではBar
)
SOURCEの後に/
を配置する必要があります(例ではFoo/
)。そうしないと、コンテンツではなくSOURCEフォルダがコピーされます。