Я пытаюсь написать скрипт, который будет искать каталог для папки и перемещать содержимое папок на один каталог вверх от их местоположения. это то, что я имею до сих пор:
find ./localFolders -name 'file' -type d -exec mv {}/* .. \;
Я думаю, что моя проблема заключается в каталоге назначения ..
. возможно я выражаю это неправильно?
Любая помощь полезна.
* редактировать **
, чтобы упростить эту проблему. Более подробная информация
Я из организации, из которой она пытается уйти MS Exchange для Zimbra. В рамках нашей миграции мы нашли отличные утилиты, которые переносят почтовые ящики, но передача файлов PST в пригодный для использования формат Zimbra оказывается сложной задачей.
Я нашел несколько решений, хотя для краткости я смог раскрутить pst-файлы в пригодный для использования формат с одним исключением -
вместо того, чтобы помещать почту в эту папку. создается подкаталог с именем “mbox”
, по-видимому, напоминающий файл mbox, из которого вырываются файлы .eml. Поскольку каждый пользователь отличается и использует разные структуры папок от других пользователей, каждый каталог неизвестен до тех пор, пока не будет запущен сценарий. Кроме того, содержимое папки mbox также является уникальным.
Поскольку папка с именем mbox является единственной константой в этих каталогах, я пытаюсь использовать команду find, чтобы найти эти папки, взять содержимое этих папок и переместить их в один каталог, а затем удалить папку с именем mbox. Вот фактическая команда, как она появляется в моем сценарии:
find localFolders -name mbox -type d -exec mv {}/* .. \;
или в приведенном вами примере:
find localFolders -name mbox -type d -execdir sh -c 'echo mv {}/* ..' \;
Я пытаюсь использовать *
в качестве подстановочного знака выбрать все в папке mbox. Насколько я могу судить, вместо этого он рассматривается как часть каталога, а не как подстановочный знак, как предполагалось
мысли?
Как насчет этого?
find ./localFolders -name 'file' -type d -execdir bash -c 'mv -vnt . -- "$0"/*' {} \; -prune
Безопасный относительно пробелов и забавных символов в именах файлов.Приятного отдыха!
Чтобы правильно делать то, что вы хотите, используя find
, вы должны понимать следующие понятия:
Каждый процесс в linux имеет рабочий каталог как часть своего внутреннего состояния. Вы можете представить его как «местоположение» процесса в файловой системе. Оболочка также является процессом и также имеет рабочий каталог. Рабочий каталог оболочки - это каталог (обычно), отображаемый в вашем приглашении.
Когда процесс создается, он наследует рабочий каталог от своего родителя. Если вы запускаете процесс из оболочки, то оболочка является родительской. Каждый процесс может изменить свой рабочий каталог по желанию. Вы можете изменить рабочий каталог оболочки, используя встроенную команду cd
.
Рабочий каталог используется при работе с относительными именами файлов. Относительные имена файлов - это имена файлов, которые не начинаются с /
. Например, когда вы делаете cat foo
, он ищет файл foo
в текущем рабочем каталоге, но когда вы делаете cat /tmp/foo
, он ищет файл foo
в /tmp
.
При работе с find -exec
вам всегда нужно думать о рабочем каталоге. Рабочий каталог -exec
является рабочим каталогом find
. Рабочий каталог find
является рабочим каталогом оболочки.
В вашем случае:
find ./localFolders -name 'file' -type d -exec mv {}/* .. \;
..
будет ссылаться на родительский каталог рабочего каталога mv
, который является рабочим каталогом -exec
, который является рабочим каталогом find
, который является рабочим каталогом оболочки к моменту выполнения команды. Это не то, что вы хотели.
Существует -execdir
, который похож на -exec
, но сначала он переключает рабочий каталог в каталог, где найден соответствующий элемент. -execdir
- это огромный шаг к решению вашего вопроса, но в вашей команде find
есть еще одна проблема: *
a.k.a. glob.
Глоб - это что-то вроде подстановочного знака. Например, foo*
будет соответствовать foobar
и foobaz
(и foo
, потому что *
также соответствует пустой строке). Все идет нормально. Интересная часть globbing заключается в том, что это выполняется оболочкой, а не исполняемой командой. Когда вы выполняете rm foo*
, оболочка сначала расширяет *
до foobar
и foobaz
, а затем выполняет rm foobar foobaz
. rm
никогда не видит *
.
Что происходит, если в текущем каталоге нет файлов, начинающихся с foo
? Тогда оболочка (обычно) не расширит *
и передаст *
команде дословно. Это означает, что rm foo*
будет выполняться как rm foo*
. rm
будет искать файл с именем foo*
, и он (скорее всего) не найдет его и прервет с ошибкой. Если вам интересно: да, имя файла может содержать *
, нет, не пытайтесь сделать это дома.
В вашем случае:
find ./localFolders -name 'file' -type d -exec mv {}/* .. \;
Перед выполнением команды find
оболочка сначала попытается расширить глобус {}/*
. Нет файлов, соответствующих шаблону {}/*
, поэтому глобус будет передан дословно.
Посмотрим, что делает команда find
. Предположим, вы выполняете команду find
из /home/username/somedir
, и существует каталог /home/username/somedir/localFolders/foodir/file
с некоторыми файлами в нем. find
начнет поиск в /home/username/somedir/localFolders
, потому что это указано в параметрах, но рабочий каталог find
- /home/username/somedir
, потому что он был выполнен оттуда.
Теперь find
найден каталог /home/username/somedir/localFolders/foodir/file
. Перед выполнением -exec
он заменит {}
найденным элементом. Это означает, что mv {}/* ..
станет mv /home/username/somedir/localFolders/foodir/file/* ..
. mv
потерпит неудачу, потому что он (скорее всего) не найдет файл с именем *
.
Предположим, что существует файл с именем *
, затем mv
переместит файл в ..
. Помните, что рабочим каталогом является /home/username/somedir
. Это означает, что mv
переместит файл в /home/username/somedir/..
, то есть /home/username
. Это не то, что вы хотели.
«Исправление» для вашей команды find
зависит от нескольких факторов. Например:
file
? Dotfiles - это файлы с именами, начинающимися с точки. Глобус *
(обычно) не будет расширяться до имен файлов, начинающихся с точки. file
? find
попытаются вернуться к ним, но потерпят неудачу, потому что они были перемещены. file
в каталоге file
? Куда должны идти эти файлы? file
файлы gazillion? Это может испортить расширение глобуса *
. file
? Должны ли они быть перезаписаны? Чтобы исправить вашу команду find
, я с радостью проигнорирую все эти факторы.
Вот исправление, использующее -execdir
и sh -c
для задержки расширения *
:
find ./localFolders -name file -type d -execdir sh -c 'mv {}/* ..' \;
Поскольку *
находится в кавычках, оно не будет расширено раньше времени. Когда -execdir
выполнит команду, sh -c
развернет *
в рабочем каталоге.
Вот еще одно исправление без sh -c
:
find ./localFolders -path "*/file/*" -execdir mv {} .. \;
Я использовал -path
, чтобы найти все элементы в каталогах с именем file
. *
заключены в кавычки, поэтому они не будут расширены раньше времени. На этот раз find
занимается интерпретацией *
. Обратите внимание, что это также будет соответствовать что-то вроде ./localFolders/foodir/file/bardir/file/somefile
. Как я уже сказал, я с радостью проигнорировал этот фактор.
И ради полноты еще одно исправление без -execdir
:
find ./localFolders -name file -type d -exec sh -c 'mv {}/* {}/..' \;