Як ви переміщуєте всі файли (включаючи приховані) з одного каталогу в інший?


132

Як перенести всі файли в каталозі (включаючи приховані) до іншого каталогу?

Наприклад, якщо у мене папка "Foo" з файлами ".hidden" і "notHidden" всередині, як я можу перемістити обидва файли до каталогу під назвою "Bar"? Далі не працює, оскільки ".hidden" файл залишається у "Foo".

mv Foo/* Bar/

Спробуйте самі.

mkdir Foo
mkdir Bar
touch Foo/.hidden
touch Foo/notHidden
mv Foo/* Bar/


Ба, я знав, що мені слід було б оновити відповіді, перш ніж набирати свої. Дуже корисне посилання.
Стівен Д

На жаль, це питання опинилося тут, тому що я сказав на ТАК, що він повинен рухатись сюди або SU, тому, звичайно, він перемістився сюди, коли вже був дублікат на SU :)
Michael Mrozek

Особисто я вважаю, що * nix конкретні питання та відповіді повинні бути поза темою щодо SU. Із чинними правилами ми закінчуємо тоннами зіткнень вмісту між цими двома - як це питання.
Cory Klein

Відповіді:


151

Зш

mv Foo/*(DN) Bar/

або

setopt -s glob_dots
mv Foo/*(N) Bar/

(Вийдіть, (N)якщо знаєте, що каталог не порожній.)

Баш

shopt -s dotglob nullglob
mv Foo/* Bar/

Кш93

Якщо ви знаєте, що каталог не порожній:

FIGNORE='.?(.)'
mv Foo/* Bar/

Стандарт (POSIX) ш

for x in Foo/* Foo/.[!.]* Foo/..?*; do
  if [ -e "$x" ]; then mv -- "$x" Bar/; fi
done

Якщо ви готові дозволити mvкоманді повернути статус помилки, навіть якщо це вдалося, це набагато простіше:

mv Foo/* Foo/.[!.]* Foo/..?* Bar/

GNU знайти та GNU mv

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змінна , яку ви можете встановити на відокремлений двокрапкою список шаблонів, що ігноруються. Якщо не встановлено (налаштування за замовчуванням), оболонка поводиться так, як якщо б значення було порожнім, якщо dotglobвоно встановлено, і як би значення було, .*якщо параметр не встановлено. Див. Розширення назви файлів у посібнику. Поширені каталоги .та ..завжди опущені, якщо тільки .явно не узгоджено за шаблоном.

$ GLOBIGNORE='n*'
$ echo *
..two .one zero
$ echo .*
..two .one
$ unset GLOBIGNORE
$ echo .*
. .. ..two .one
$ GLOBIGNORE=.:..
$ echo .*
..two .one

Кш93

Встановити FIGNOREзмінну . Якщо не встановлено (налаштування за замовчуванням), оболонка поводиться так, як якщо б значення було .*. Для того, щоб ігнорувати .і ..вони повинні бути узгоджені в явному вигляді (керівництво в КШ 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 класифікатором глобу .

% echo *(D)
..two .one none zero

Додайте NГлоб класифікатор , щоб зробити розширення вийти порожній в порожньому каталозі: *(DN).


Примітка: ви можете отримати ім'я файлу результатів розширення в різних порядках (наприклад, з noneподальшим .oneподальшим ..two) , грунтуючись на ваших налаштуваннях LC_COLLATE, LC_ALLі LANGзмінних.


1
Чому nullglob? Було б більше сенсу відміняти mvкоманду (наприклад, fish, csh / tcsh, zsh (без (N)) do, або грати з failglob), ніж виконувати mv /Bar/команду, яка має мало сенсу.
Стефан Шазелас

1
Я б сказав, що ваш опис GLOBIGNORE неточний та оманливий. Якщо встановити значення GLOBIGNORE на не порожнє значення, увімкніть dotglob і зробить це .і ..ніколи не збігається (як у інших чутливих оболонках, таких як zsh, fish, pdksh та похідні), навіть якщо згодом вимкніть dotglob. ( GLOBIGNORE=:; shopt -u dotglob; echo .*не виводиться .і ..). установка GLOBIGNORE до .:..або .або :мати той же ефект.
Стефан Шазелас

ksh93завжди ігноруючи .і, ..здається, зламаний між ksh93k+(де він працював) і ksh93m(там, де він більше не працює). Зауважте, що це погано в тому, що ksh93буде приймати значення FIGNORE з оточення, тому FIGNORE='!(..)'env var, наприклад, може створити хаос.
Стефан Шазелас

24
#!/bin/bash

shopt -s dotglob
mv Foo/* Bar/

З man bash

dotglob Якщо встановлено, bash включає в себе назви файлів, що починаються з '.' в результатах розширення імені шляху.


З застереженням, що ця команда повертає код помилки, якщо каталог був порожнім (навіть незважаючи на те, що команда насправді виконувалася за призначенням).
Жиль

1
@Gilles, помилка буде потім mvскаржитися на те, що названий файл Foo/*не існує. Цікаво, що якщо ви Fooможете шукати, але не читати, і там є файл, викликаний *там, ви не отримаєте помилок, цей файл буде переміщений, але не інші з каталогу. bashє failglobваріант, тому він поводиться більше zsh, fishабо csh/ tcshі скасовує команду з помилкою, коли глобус не може бути розширений замість такої хибної поведінки залишити глобус таким, який є.
Стефан Шазелас

7

Простий спосіб зробити це bash- це

mv {Foo/*,Foo/.*} Bar/

Але це також перемістить каталоги.

Якщо ви хочете перемістити всі файли, включаючи приховані, але не хочете переміщувати жоден каталог, ви можете скористатися циклом та тестом.

for i in $(ls -d {Foo/*,Foo/.*});do test -f $i && mv -v $i Bar/; done;


4

Одним із способів є використання find:

find Foo/ -type f -exec mv -t Bar/ {} \+

Команда -type ffind обмежує пошук файлів. Ви повинні проаналізувати -type, -maxdepthі -mindepthваріанти , findщоб налаштувати команду на рахунок для підкаталогів. Find має довгу, але дуже корисну сторінку вручну .


3
Це переміщує лише звичайні файли Foo/, а не підкаталоги та інші файли.
Жиль

2

Спробуйте скопіювати команду cp:

$ cp -r myfolder/* destinationfolder

cp -r означає рекурсивну копію, тому всі папки та файли будуть скопійовані.

Ви можете скористатися командою delete rmдля видалення папки:

$ rm -r myfolder

Докладніше: переміщення всіх файлів з каталогу в інший .


2
Не найкраще, коли ви переміщуєте багато великих файлів, але я думаю, це спрацювало б.
Cory Klein

Може, якщо ви використовуєте крапку замість зірки?
Вінсент

1

Rsync - це ще один варіант:

rsync -axvP --remove-source-files sourcedirectory/ targetdirectory

Це працює, тому що в rsync важливий ривок косої риси sourcedirectory/посилається на вміст каталогу, в той час як sourcedirectoryбуде посилатися на сам каталог.

Недоліком цього методу є те, що rsync очищатиме файли лише після переміщення, а не каталогів. Отже, вам залишається порожнє дерево з каталогів. Для вирішення цього питання див.

Перемістити файли та видалити каталоги за допомогою rsync?

Тому, хоча це не може бути оптимальним для операцій переміщення, воно може бути надзвичайно корисним для операцій з копіюванням.


1

Відповідь на баш / рибу

Ось спосіб зробити це за допомогою макіяжів:

.[!.]* ..?*відповідатиме всім прихованим файлам, крім .і..

.[!.]* ..?* *відповідатиме всім файлам (приховано чи ні), крім .і..

І щоб відповісти на конкретний приклад цього питання, вам потрібно cd foo && mv .[!.]* ..?* * ../bar

Пояснення

.[!.]*відповідає іменам файлів, що починаються з однієї крапки, за якою слід будь-який символ, за винятком крапки, необов'язково і будь-якого рядка. Це досить близько, але у ньому відсутні файли, починаючи з двох крапок ..foo. Для включення таких файлів ми додаємо, ..?*які збігаються з іменами файлів, починаючи з двох крапок, а потім будь-який символ, за бажанням слід будь-який рядок.

Тест

Ви можете перевірити ці символи за допомогою наведених нижче команд. Я їх успішно пробував у баш та рибі. Вони провалюються під 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

0

Можливо, ви також зможете знайти і скопіювати зворотні цитати, щоб вибрати файли для команди переміщення. Передайте їх у 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шаблонів можна знайти тут .

Використовуючи maxdepth 1зупинки, знаходьтесь у підкаталогах.


0

Натхненник цієї відповіді :

Без копіювання файлів ...

rsync -ax --link-dest=../Foo/ Foo/ Bar

Застереження:

  • --link-destшлях повинен бути абсолютним або відносно DESTINATION ( Bar у прикладі)

  • Ви повинні поставити /після SOURCE ( Foo/у прикладі), інакше вона скопіює папку SOURCE замість вмісту.


0

Я вважаю, що це добре працює для bash і не потрібно змінювати параметри оболонки

mv sourcedir/{*,.[^.]*} destdir/

Редагувати:

Отже, як зазначив G-man, моя оригінальна відповідь не відповідає позі, і це майже те саме, що відповідь ndemou вище однією зміною, яка полягає у використанні розширення дужок для створення списків рядків, на які потім діяли. Це просто означає, що вам не потрібно cdпотрапляти у вихідний каталог. Не така велика зміна насправді, але вона інша.

приклад: скажімо, у вас уже є такий макет.

 $ tree -a
.
├── destdir
└── sourcedir
    ├── ..d1
    ├── ..d2
    ├── ..double
    ├── file-1
    ├── file-2
    ├── .hidden-1
    ├── .hidden-2
    ├── ...t1
    └── ...t2

У початковому запитанні згадувалися лише приховані файли з одним періодом, але скажімо, що на початку імені є деякі з двома або більше періодами. Ви можете просто додати додатковий вираз у дужки. Потім ми можемо виконати

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. Ознайомтеся з хакерами-хакерами на кілька прекрасних прикладів.


1
Це в основному дублює відповідь ndemou, за винятком того, що ви додали фігурні дужки (не пояснюючи їх). Але (1) ваша відповідь не відповідає файлам, імена яких починаються з .., і (2) бути сумісними з POSIX , ви повинні використовувати !замість ^; тобто  {*,.[!.]*}.
G-Man

@ G-Man, вибач за це. Отже, ви маєте рацію і мені погано, що не бачили відповіді ndemou. Вони майже однакове. 1. дякую за те, що вказали, що моя версія не відповідає стандарту posix. 2. Я використовую розширення дужок, щоб створити списки рядків, які потім оболонка буде використовуватись для виконання дії. Це також означає, що мені не потрібно cdвходити в каталог джерел, щоб діяти на файли або виписувати однакові шляхи до файлів знову і знову, щоб виразити шляхи до всіх файлів. Незабаром оновлю приклад, щоб дати читачам кращу картину того, про що я говорю.
cmndr sp0ck

0

Для мінімальних дистрибутивів Linux повинні працювати наступні. По-перше, виконайте основний хід усіх (який пропускає приховані файли). Потім перемістіть усі приховані файли (в тому числі .і ті, ..які фактично не будуть переміщені).

mv /sourceDir/* /destinationDir 2> /dev/null
mv /sourceDir/.* /destinationDir 2> /dev/null

Примітки: Якщо видимого вмісту немає, перша команда видасть повідомлення про помилку. Друга команда завжди створюватиме помилку, кажучи, що вона не може рухатися .та ... Таким чином, просто передайте помилки /dev/null(як показано).

Якщо вам це потрібно як однолінійний, просто поєднайте їх із комою:

mv /sourceDir/* /destinationDir 2> /dev/null; mv /sourceDir/.* /destinationDir 2> /dev/null
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.