Значение всех опций написано в справочной странице:
-R, --randomwait=[time in minutes]
Sets the maximum amount of time yum will wait before performing a command -
it randomizes over the time.
-d, --debuglevel=[number]
Sets the debugging level to [number] - turns up or down the amount of things
that are printed. Practical range: 0 - 10
-e, --errorlevel=[number]
Sets the error level to [number] Practical range 0 - 10. 0 means print only critical
errors about which you must be told. 1 means print all errors, even ones that are
not overly important. 1+ means print more errors (if any) -e 0 is good for cron jobs.
Итак, /usr/bin/yum -y -R 120 -d 0 -e 0 update yum
обновляет пакет yum
после произвольного ожидания до 2 часов, выводя только критические ошибки.
У вас уже почти все получилось. Вы можете выбрать другое имя для переходного каталога, например, целевое имя с текущей датой/временем в наносекундах и наш PID в качестве составного суффикса, но это по-прежнему предполагает, что каталог еще не существует :
.dir=foo # The directory we want to nest
now=$(date +'%s_%N') # Seconds and nanoseconds
mkdir "$dir.$now.$$" # Create a transient directory
mv -f "$dir" "$dir.$now.$$/" # Move our directory inside transient directory
mv -f "$dir.$now.$$" "$dir" # Rename the transient directory to the name with which we started
Если вам нужно гарантированно надежное решение, я бы перебирал mkdir
до тех пор, пока оно не было успешным
now=$(date +'%s_%N')
while ! mkdir -m700 "$dir.$now.$$" 2>/dev/null
do
sleep 0.$$
now=$(date +'%s_%N')
done
Чтобы безопасно создать временный каталог в текущем каталоге с именем, которое еще не занято, вы можете использовать mktemp -d
вот так:
tmpdir=$(mktemp -d "$PWD"/tmp.XXXXXXXX) # using./tmp.XXXXXXXX would work too
Команда mktemp -d
создаст каталог по указанному пути, заменивX
-es в конце пути на случайные буквенно-цифровые символы. Он вернет путь к созданному каталогу, и мы сохраним это значение в tmpdir
. 1
Эту переменную tmpdir
затем можно использовать при выполнении той же процедуры, которую вы уже выполняете, с заменой bar
на"$tmpdir"
:
mv foo "$tmpdir"
mv "$tmpdir" foo
unset tmpdir
unset tmpdir
в конце просто удаляет переменную.
1Обычно один должен иметь возможность установить переменную среды TMPDIR
на путь к каталогу, в котором нужно создать временные файлы или каталоги с помощью mktemp
, но утилита в macOS похоже, что эта утилита работает несколько иначе, чем та же утилита в других системах BSD, и создаст каталог в совершенно другом месте. Вышеупомянутое, однако, будет работать на macOS. Использование немного более удобного tmpdir=$(TMPDIR=$PWD mktemp -d)
или даже tmpdir=$(TMPDIR=. mktemp -d)
было бы проблемой только в macOS, если временный каталог по умолчанию находился в другом разделе, а каталог foo
содержал много данных (, т.е. это было бы медленно ).
Я предлагаю наоборот. Не перемещайте каталог, а только его содержимое:
.
└── foo
├── a.txt
└── b.txt
mkdir foo/foo
.
└── foo
├── foo
├── a.txt
└── b.txt
cd foo
mv $(ls | grep -v '^foo$') foo
cd -
.
└── foo
└── foo
├── a.txt
└── b.txt
Если у вас есть bash, вы также можете
shopt -s extglob
cd foo
mv !(foo) foo
cd -
(как описано здесь ), чтобы избежать запуска ls и grep.
Преимущество этого решения в том, что оно очень простое.
Недостатки (как указано в комментариях):
ls -A
исправляет, но неls -a
)mv "$(ls | grep -v '^foo$')" foo
Большинство недостатков можно устранить с помощью некоторого трюка с bash, но если нужно обрабатывать сумасшедшие имена файлов, лучше использовать более надежный подход, как описано в других ответах.
В macOS вы можете установить rename
команду (Perl-скрипт )с помощью Homebrew:
brew install rename
Затем с помощью-p
(а-ляmkdir
)создайте необходимые каталоги и -A
добавьте префикс:
% mkdir -p foo/bar; touch foo/{a,b}.txt foo/bar/c.txt
% rename -p -A foo/ foo/*
% tree foo
foo
└── foo
├── a.txt
├── b.txt
└── bar
└── c.txt
Прогон с -n
для отображения изменений без переименования (пробный прогон -прогон):
% rename -p -A foo/ foo/* -n
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/bar' would be renamed to 'foo/foo/bar'
Если у вас точечные файлы, так что простой *
их не подхватит, то используйте другие методы сrename
:
С помощью bash (mis )используйте GLOBIGNORE
, чтобы получить *
для соответствия файлам точек:
$ GLOBIGNORE=.; rename -p -A foo/ foo/* -n
'foo/.baz' would be renamed to 'foo/foo/.baz'
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/bar' would be renamed to 'foo/foo/bar'
Или используйте find
с -print0
и rename
с-0
:
% find foo -mindepth 1 -maxdepth 1 -print0 | rename -0 -p -A foo/ -n
Reading filenames from STDIN
Splitting on NUL bytes
'foo/b.txt' would be renamed to 'foo/foo/b.txt'
'foo/a.txt' would be renamed to 'foo/foo/a.txt'
'foo/bar' would be renamed to 'foo/foo/bar'
'foo/.baz' would be renamed to 'foo/foo/.baz'
Пока содержимого недостаточно, чтобы превысить максимальные пределы параметров, (и вы не возражаете против «приемлемого» сообщения об ошибке ), тогда это не должно быть более сложным, чем это:
mkdir foo/foo
mv foo/* foo/foo
Поправка для обработки скрытых файлов:
mkdir foo/foo
mv foo/{.,}* foo/foo
mkdir foo/foo && mv foo/!(foo) foo/foo
Вам нужно перейти в каталог, где находится исходная папка (foo ).
Затем выполните приведенную выше команду. Он создаст папку с тем же именем и переместит содержимое родительского foo в дочерний каталог foo (, за исключением дочернего каталога, поэтому ! обозначение ).
Если дочерний каталог foo уже существует, вы можете игнорировать первую часть и просто запустить команду mv:
mv foo/!(foo) foo/foo
В MacOS вам может потребоваться установить параметр extglob:
shopt -s extglob
В дополнение к приведенным выше предложениям вы можете проверить rsync. Прежде чем я начну, всегда не забывайте использовать параметр --dry-run
с rsync, прежде чем запускать его без него. --dry-run
расскажет вам, что произошло бы в реальной жизни.
У rsync есть множество опций, которые могут не только помочь копировать/переместить файлы, но и ускорить процесс. Вот один из способов выполнить свою работу. Опция --remove-source-files
удаляет файлы из источника после процесса перемещения (, который фактически является копией, за которой следует удаление ). Обратите внимание, что команда rsync сначала считывает содержимое foo, создает каталог foo в существующем каталоге с именем foo, а затем запускает процесс копирования. Это заканчивается удалением исходных файлов в foo. Предостережение :Обратите особое внимание на символы косой черты в именах каталогов.
Есть и другие соображения, на которые многие указывали выше (, такие как символические ссылки ), но man rsync
поможет вам выбрать нужные параметры. Примечание здесь :Поскольку вы просили решение для файлов, это сработает. Это не удалит пустые каталоги, которые останутся позади. Я не знаю, как это сделать без дополнительного шага, поэтому, если кто-то может что-то добавить, заранее спасибо!
mkdir foo
cd foo
touch aaa bbb ccc ddd
cd..
rsync -av --remove-source-files foo foo/
a = режим архива
v = подробный
Просто не трогайте foo, и у вас не будет проблем с одинаковыми именами. Вместо этого создайте внутри него каталог с таким же именем и переместите все туда. Используйте трюк $ _для этого и &&, чтобы сделать его одним -лайнером:
cd foo && mkdir $_ && mv * $_
Это вызовет безобидную ошибку.(mv :переименовать foo в foo/foo :Недопустимый аргумент ), который можно игнорировать.
Преимущество перед другими ответами :Вам нужно ввести имя каталога только один раз, поэтому вы не допустите ошибок с опечатками.
вы можете смешать это с другими ответами для еще большего эффекта:
mv {.,}* $_
позаботится о скрытых файлах (за счет большего количества ошибок, которые вы также можете игнорировать)mv./!(foo)
позволит избежать сообщения об ошибке, но только если вы установитеshopt -s extglob
Это на самом деле обманчиво просто, и я в шоке, что никто еще не предложил такой ответ, так что начнем. Например, используя следующее...
$ mkdir foo
$ mkdir bar
$ mkdir./bar/foo
$ touch./bar/foo/file1 && touch./bar/foo/file2 && touch./bar/foo/file3
$ ls./
bar/ foo/
$ ls./bar/foo
file1 file2 file3
А теперь волшебная часть
$ mv./bar/foo./foo/
$ ls./foo/
foo/
$ ls./foo/foo/
file1 file2 file3
Теперь, почему это работает? Я не могу дать вам самый точный ответ, так как я всего лишь новичок -, но я понимаю, что все сводится к тому, как конечные /
символы обрабатываются в папках.
Посмотрите внимательно на эту команду mv
$ mv./bar/foo./foo/
Обратите внимание, что целевая папка с файлами указана без завершающего /
, в то время как пункт назначения, использующий имя целевой папки, указывается с помощью завершающего /
'. Это ваш волшебный билет, и он может укусить вас за задницу, если вы не будете внимательны.
Мне жаль, что я не могу предложить более развернутый ответ, чем этот, но, возможно, кто-то более свободно осведомленный возьмет на себя смелость отредактировать мой ответ.
Во всяком случае, это кажется самым простым и прямым решением,с однократным использованием команды ls
и без создания промежуточных папок.
Надеюсь, вам это поможет!