Я хотел бы найти новый каталог в каталоге и сохранить результат в переменной в bash.
Что-то вроде этого:
ls -t /backups | head -1 > $BACKUPDIR
Может ли кто-нибудь помочь?
Я хотел бы найти новый каталог в каталоге и сохранить результат в переменной в bash.
Что-то вроде этого:
ls -t /backups | head -1 > $BACKUPDIR
Может ли кто-нибудь помочь?
BACKUPDIR=$(ls -t /backups | head -1)
$(...) оценивает оператор в подоболочке и возвращает результат.
Это простое решение, использующее только ls:
BACKUPDIR=$(ls -td /backups/*/ | head -1)
-t заказы по времени (последняя первая)-d перечисляет только элементы из этой папки*/ перечислены только каталогиhead -1 возвращает первый элементЯ не знал о */, пока не нашел Список только каталогов, использующих ls в bash: Экзамен.
В приведенном выше решении не учитываются такие вещи, как файлы, которые пишутся и удаляются из каталога, в результате чего возвращается верхний каталог вместо нового подкаталога.
Другая проблема заключается в том, что это решение предполагает, что каталог содержит только другие каталоги, а не записываемые файлы.
Скажем, я создаю файл с именем test.txt и снова запустил эту команду:
echo "test" > test.txt
ls -t /backups | head -1
test.txt
В результате появляется test.txt вместо последнего измененного каталога.
Предлагаемое решение "работает", но только в лучшем случае.
Предполагая, что у вас максимум 1 глубина каталогов, лучше использовать следующее:
find /backups/* -type d -prune -exec ls -d {} \; |tail -1
Просто замените часть "/backups/" для вашего фактического пути.
Если вы хотите избежать абсолютного пути в bash script, вы всегда можете использовать что-то вроде этого:
LOCALPATH=/backups
DIRECTORY=$(cd $LOCALPATH; find * -type d -prune -exec ls -d {} \; |tail -1)
Чтобы получить новую папку с помощью ls -t, возможно, вам придется различать файлы из папок, если в вашем каталоге нет только каталогов. Используя простой цикл, вы получите быстрый и быстрый результат, а также сможете легко реализовать различные фильтры в будущем:
while read i ; do if [ -d "${i}" ] ; then newestFolder="${i}" ; break ; fi ; done < <(ls -t)
Разработанный блок:
while read currentItemOnLoop # While reading each line of the file
do
if [ -d "${currentItemOnLoop}" ] # If the item is a folder
then
newestFolder="${currentItemOnLoop}" # Then save it into the "newestFolder" variable
break # and stop the loop
else
continue # Look for the next newest item
fi
done < <(ls -t) # Sending the result of "ls -t" as a "file" to the "while read" loop
Остерегайтесь логики continue в моем разработанном блоке:
else
continue # Look for the next newest item
Вы не будете использовать его. Я разместил его только ради вашей видимости, так как в этом случае это не повлияет на результаты.
Ну, я думаю, что это решение является наиболее эффективным:
path="/my/dir/structure/*"
backupdir=$(find $path -type d -prune | tail -n 1)
Объяснение, почему это немного лучше:
Нам не нужны суб-оболочки (кроме одного для получения результата в переменной bash).
Нам не нужен бесполезный -exec ls -d в конце команды find, он уже распечатывает список каталогов.
Мы можем легко изменить это, например. чтобы исключить определенные шаблоны. Например, если вы хотите второй новейший каталог, потому что файлы резервных копий сначала записываются в каталог tmp по тому же пути:
backupdir=$(find $path -type -d -prune -not -name "*temp_dir" | tail -n 1)
Это чистое решение Bash:
topdir=/backups
BACKUPDIR=
# Handle subdirectories beginning with '.', and empty $topdir
shopt -s dotglob nullglob
for file in "$topdir"/* ; do
[[ -L $file || ! -d $file ]] && continue
[[ -z $BACKUPDIR || $file -nt $BACKUPDIR ]] && BACKUPDIR=$file
done
printf 'BACKUPDIR=%q\n' "$BACKUPDIR"
Он пропускает символические ссылки, включая символические ссылки на каталоги, которые могут или не могут быть правильными. Он пропускает другие не-каталоги. Он обрабатывает каталоги, имена которых содержат любые символы, включая символы новой строки и ведущие точки.