У меня в / home / около 200 каталогов. Проблема в том, что все они существуют таким образом:
/ home / {user} / homedir /
Хотя должно быть просто:
/ home / {user} /
С помощью какой команды я могу массово перемещать все содержимое домашнего каталога на один каталог вверх для каждого пользователя?
Спасибо за помощь.
Это может отличаться в зависимости от вашей оболочки, но при условии, что bash:
for a in $(find /home -maxdepth 1 -type d); do mv $a/homedir/* $a/; rmdir $a/homedir; done
Запустить find
отдельно, чтобы убедиться, что список соответствует вашим ожиданиям, прежде чем запускать полную команду и удалять rmdir
часть, если вы хотите оставить пустым homedir
в каждой папке.
Если вы не превысите длину командной строки с помощью глобусов mv /home/*/* /home
должно сработать. Обратите внимание, если у вас есть файлы в /home/user
они также будут перемещены в /home
.
Переместите содержимое домашнего каталога вверх по каталогу:
cd /home
for i in */homedir; do /bin/mv $i/* $i/.. && /bin/rmdir $i; done
Вот более параноидальный сценарий, который избегает всех имен пользователей (использует "@@@" для каталога tmp), сохраняет точечные файлы, которые отбрасывает "mv $ a / homedir / *", останавливается, если каталог @@@ не согласован, и не должно быть проблем с длиной команды. Оставшаяся слабость - патологические имена пользователей.
cd /home
ls -1 | while read user ; do # allow many user dirs without imploding
[ -d @@@ ] && { echo tmp already present, aborting 1>&2 ; exit 1 ; }
mv $user @@@
mv @@@/homedir $user
rmdir @@@ || { echo tmp dir for $user not empty, aborting 1>&2 ; exit 2 ; }
done
Подход find () является хорошим выбором, если вся команда для каталога была похоронена в -exec, как в:
cd /home && find -name . -o -type d -prune -print \
-exec mv '{}' @@@ ';' \
-exec mv @@@/homedir '{}' ';' \
-exec rmdir @@@ ';'
Пробовать что-то вроде "for f in $(find ....)"
является хрупким, поскольку оболочки сначала захотят развернуть всю командную строку. Показанные здесь находки зависят от расширения {} с помощью поиска даже внутри строк, что, я не уверен, все находят поддержку.
или даже
cd /home && find -name . -o -type d -prune -print -exec \
sh -c 'mv {} @@@ && mv @@@/homedir {} && rmdir @@@' ';'
Тестирование:
mkdir -p {fred,jan,alice}/homedir
touch {fred,jan,alice}/homedir/.dotstuff
touch {fred,jan,alice}/homedir/stuff
Пусть один рип (без "cd / home") и посмотрим, как это получается. Кажется, здесь все работает хорошо.
Решение SmallClanger можно изменить, так что пробелы не будут проблемой. Уловка состоит в том, чтобы изменить внутренний разделитель полей Bash, который представляет собой переменную, вызываемую IFS и обычно содержит пробел и новую строку, чтобы просто содержать новую строку. Такие как:
IFS=$'\n'
Это изменит IFS на символ новой строки для вашей текущей оболочки.
После этого вы можете запустить команду SmallClanger или что-то подобное:
for item in $(find ./homedir -mindepth 1 -maxdepth 1 -type d); do
echo " --> \"$item\"" >&2
mv "$item" .
done
Предполагается, что ваш рабочий каталог - "/ home / {user}".
Вы можете опустить строку "mv" при первой попытке увидеть, что содержит $ item. Если он выглядит хорошо, вы запускаете его с помощью «mv». Не забывайте двойные кавычки вокруг «$ item».
Таким образом, вы столкнетесь с проблемами только в том случае, если какой-либо из ваших путей к файлу или папке содержит символы новой строки, которые я считаю гораздо более необычными, чем те, которые содержат пробелы.
Немного информации о внутреннем разделителе полей: Bash: внутренние переменные
Я также думаю, что вы можете сделать так, чтобы программа "find" выдавала свои результаты через NUL. Если возможно установить IFS на NUL, вы должны быть в безопасности практически для всего, поскольку обычно NUL не является допустимой кодовой точкой для файлов / каталогов в большинстве файловых систем. Но сам я никогда не пробовал.
Я бы просто
cd /home/user/
mv homedir/* .