LINUX.ORG.RU

Как обновить ataime в каталога по файлам и подкаталогам в нём?


0

0

Задача: поиск подкаталогов, к файлам которых давно не было обращений. Т.е. надо рекурсивно «с самого дна» прописать всем каталогам самый свежий atime содержащихся в нём каталогов и подкаталогов.

В голову приходит только скрипт на Perl/Python/PHP.

Нет ли более простого решения?

★★★★★
Ответ на: комментарий от redgremlin

Очень много писанины.

Ладно, слепил таки скрипт. М.б. кому пригодится:

#!/usr/bin/env python

import sys
import os
from stat import ST_ATIME, ST_MTIME

def fileatime(file):
	try:
		stat = os.stat(file)
		return stat[ST_ATIME]
	except:
		print "Can't get atime for ", file
		return 0

def filemtime(file):
	try:
		stat = os.stat(file)
		return stat[ST_MTIME]
	except:
		print "Can't get mtime for ", file
		return 0

def atime_update(dir):
	amax = 0
	mmax = 0
	try:
		list = os.listdir(dir)
	except os.error:
		sys.stderr.write(dir + ': cannot list\n')
		list = ()

	for x in list:
		check = os.path.join(dir,x)
		if os.path.isdir(check) and not os.path.islink(check):
			atime_update(check)
		atime = fileatime(check)
		mtime = filemtime(check)
		if atime > amax:
			amax = atime
		if mtime > mmax:
			mmax = mtime

	if amax > 0 and mmax > 0:
		try:
			os.utime(dir, (amax, mmax))
		except:
			pass

def main():
	if len(sys.argv) <> 2:
		sys.stderr.write('usage: atime-r-update dir\n')
		sys.exit(2)
	dir = sys.argv[1]
	atime_update(dir)

main()

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

>Очень много писанины.

O_o Это по вашему длиннее вашего скрипта:

stamp=`find . -type d -printf "%AY%Am%Ad%AH%AM.%AS\n" | sort | tail -n 1` ; find . type d -exec touch -t $stamp '{}' \;

????

redgremlin ★★★★★
()
Ответ на: комментарий от annoynimous

>не подходит?

Мне нужна не сегодняшняя дата. А дата самого старшего файла или каталога внутри.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от redgremlin

>O_o Это по вашему длиннее вашего скрипта:

Это тоже не то. Насколько я понимаю, он находит самый новый файл в подкаталогах и присваивает дату доступа к нему _всем_ подкаталогам внутри данного. А нужна строгая иерархия.

Т.е.

/d1/d2/f1 - 20 марта
/d1/d3/f2 - 22 матрта

После прохода имеем

/d1/d2 - 20 марта
/d1/d3 - 22 марта
/d1 - 22 марта

В твоём случае /d1/d2 тоже будет 22 марта.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

s/дата самого старшего файла/дата самого свежего/

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от scaldov

Вот я и спрашивал, нет ли готового решения попроще. Но быстрее было написать самому :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

Ну, дык, долго еще for приляпать?

for i in `ls` do ; stamp=`find "$i" -type d -printf "%AY%Am%Ad%AH%AM.%AS\n" | sort | tail -n 1` ; find "$i" type d -exec touch -t $stamp '{}' \; ; done

redgremlin ★★★★★
()
Ответ на: комментарий от redgremlin

В этом варианте у тебя только один уровень вложенности. Внутри каждого из подкаталогов нужно делать то же самое.

Безусловно, это всё можно в рекурсивный bash-скрипт теперь ещё запихнуть.

Но на Питоне я эту задачу решил минут за 10, а на bash'е я только ошибки буду дольше отлавливать :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от pawnhearts

>ужас...

Зато работает. И писался на коленке за 10 минут с отладкой и проверкой. Альтернативное же работающее решение в топике до сих пор предложено не было :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

> Зато работает. И писался на коленке за 10 минут
ну какбы в общем да..
но всё равно выскажу своё фи

>except:

> print "Can't get atime for ", file

эксцепшены глотать не надо никогда.. а такого рода сообщения надо печатать в stderr..
даже если лень использовать logging, как-то так
except Exception,e:
print >>sys.stderr, e
и наверное удобнее было бы использовать os.path.getatime, os.path.getmtime чем stat тут..
>except:

> pass

брр..


>list = os.listdir(dir)

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

>amax = 0

>if atime > amax:

> amax = atime

это же питон, можно было бы написать как-то типа
max(fileatime(os.path.join(path,f)) for f in os.listdir(path))
гораздо короче

> if len(sys.argv) <> 2


"<>" deprecated, надо использовать "!="

и вместо рекурсии и listdir`ов гораздо удобнее было бы использовать os.walk

итого как-то так:

import os,sys

def main(path):
for root,dirs,files in os.walk(path):
atime = max(os.path.getatime(os.path.join(root,f) for f in files)
mtime = max(os.path.getmtime(os.path.join(root,f) for f in files)
if atime and mtime:
try:
os.utime(root, (atime, mtime))
except Exception,e:
print >>sys.stderr,e

if __name__ == '__main__':
if len(sys.argv) != 2:
main(sys.argv[1])

pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

тьфу
import os,sys

def main(path):
  for root,dirs,files in os.walk(path):
    atime = max(os.path.getatime(os.path.join(root,f) for f in files)
    mtime = max(os.path.getmtime(os.path.join(root,f) for f in files)
    if atime and mtime:
      try:
        os.utime(root, (atime, mtime))
      except Exception,e:
        print >>sys.stderr,e

if __name__ == '__main__':
  if len(sys.argv) != 2:
    main(sys.argv[1])

pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

Во-первых, ты свой вариант даже не запускал ;)

Во-вторых, он работает не так, как нужно. Не обновляет дату модификации/доступа каталога уровнем выше одного от глубоко лежащего файла/каталога.

Нужно обновить всю ветку до заданного корня, если в этой ветке есть обновление.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

конечно не запускал))
> Нужно обновить всю ветку до заданного корня, если в этой ветке есть обновление.


что-то я смотрю на твой код и в упор не пойму в чем отличие..
единственное, в моем варианте должно быть "for f in files+dirs)"

pawnhearts ★★★★★
()
Ответ на: комментарий от pawnhearts

>конечно не запускал))

Это видно по синтаксической ошибке ;)

>что-то я смотрю на твой код и в упор не пойму в чем отличие..

В том, что твой код - нерекурсивный :) И не возвращается к уже пройденному.

>единственное, в моем варианте должно быть "for f in files+dirs)"

Всё равно не работает ;)

KRoN73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.