Получить новый каталог в bash для переменных

Я хотел бы найти новый каталог в каталоге и сохранить результат в переменной в bash.

Что-то вроде этого:

ls -t /backups | head -1 > $BACKUPDIR

Может ли кто-нибудь помочь?

Ответы

Ответ 1

BACKUPDIR=$(ls -t /backups | head -1)

$(...) оценивает оператор в подоболочке и возвращает результат.

Ответ 2

Это простое решение, использующее только ls:

BACKUPDIR=$(ls -td /backups/*/ | head -1)
  • -t заказы по времени (последняя первая)
  • -d перечисляет только элементы из этой папки
  • */ перечислены только каталоги
  • head -1 возвращает первый элемент

Я не знал о */, пока не нашел Список только каталогов, использующих ls в bash: Экзамен.

Ответ 3

В приведенном выше решении не учитываются такие вещи, как файлы, которые пишутся и удаляются из каталога, в результате чего возвращается верхний каталог вместо нового подкаталога.

Другая проблема заключается в том, что это решение предполагает, что каталог содержит только другие каталоги, а не записываемые файлы.

Скажем, я создаю файл с именем 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)

Ответ 4

Чтобы получить новую папку с помощью 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

Вы не будете использовать его. Я разместил его только ради вашей видимости, так как в этом случае это не повлияет на результаты.

Ответ 5

Ну, я думаю, что это решение является наиболее эффективным:

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)

Ответ 6

Это чистое решение 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"

Он пропускает символические ссылки, включая символические ссылки на каталоги, которые могут или не могут быть правильными. Он пропускает другие не-каталоги. Он обрабатывает каталоги, имена которых содержат любые символы, включая символы новой строки и ведущие точки.