Назад | Перейти на главную страницу

Как массово переместить файлы на один каталог вверх

У меня в / 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/* .