LINUX.ORG.RU

Перебор атрибутов файлов по очереди в цикле

 , ,


0

1

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

Наваял это:

#!/bin/bash
for FileList in $( ls * ); do
  #echo $FileList
  FileCreationDate=$(ls -l --time=c | awk '{print $6}')
  echo $FileCreationDate
done

Текущий вывод скрипта:

2012-11-30 2012-11-30 2012-11-30 2013-01-04 2013-01-04 2013-01-04
2012-11-30 2012-11-30 2012-11-30 2013-01-04 2013-01-04 2013-01-04
2012-11-30 2012-11-30 2012-11-30 2013-01-04 2013-01-04 2013-01-04
2012-11-30 2012-11-30 2012-11-30 2013-01-04 2013-01-04 2013-01-04
2012-11-30 2012-11-30 2012-11-30 2013-01-04 2013-01-04 2013-01-04
2012-11-30 2012-11-30 2012-11-30 2013-01-04 2013-01-04 2013-01-04
Но переменная FileList каждую итерацию принимает значение всего списка файлов. а надо бы по очереди. Хочу потом воткнуть проверку наличия директории с именем FileCreationDate в цикл. Внутрь копировать файлы с соответсвующими атрибутами. Все это затеял для сортировки фоток.) Нет, GUI утилиты использовать не хочу. Консоль быстрее, проще и хочу учиться на практических примерах использованию bash. Спасибо заранее)


С $FileList всё нормально. Там имя файла. Только вот когда время считаешь, ты делаешь листинг директории, а не конкретный файл смотришь, потому что имя переменной упустил.

Надо ls -l --time=c $FileList | awk '{print $6}'

Только в таком скрипте ты потом наткнёшься на ещё один косяк. Если в проверяемой директории помимо файлов окажутся ещё другие директории, получишь ошибку.

shell-script ★★★★★
()
Последнее исправление: shell-script (всего исправлений: 1)
Ответ на: комментарий от shell-script

Спасибо, то есть надо еще и проверку на тип файл/директория добавить?

#!/bin/bash
for FileList in $( ls * ); do
  if [ -f "$FileList" ]
  then
    FileCreationDate=$(ls -l --time=c $FileList | awk '{print $6}')
  fi  
  echo $FileCreationDate
done

вроде работает. Правильно? Или как-то иначе корректнее будет?

meklon
() автор топика

Вот, есть у меня скрипт для поиска файлов по содержимому через передаваемый параметр

$ alias
alias fgr='find -type f -print0 | xargs -0 grep -n -i $1'
Можешь по аналогии добавить те действия какие нужно через «|».

Но если предполагается использование какой-никакой логики, то я бы лучше python использовал для лучшей читабельности кода и улучшения коэффициента error-free твоего кода.

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

поправлю:-) опыта в написании мало. чем данный вариант грозит? я в каком-то мануале подобную конструкцию видел.

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

если в названии файла есть скажем перенос строки (а такое допустимо), то ls выведет его как 2 строки, а шелл считает как 2 разных значения. А так шелл сам разворачивает имена файлов. Ну и использование такой переменной стоит заключать в двойные кавычки

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

спасибо за объяснения. могу ли я потом дать вам конечный вариант просмотреть на предмет ошибок и оптимизации? Сказывается недостаток опыта:-)

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

спасибо, я совсем не знаю питон и он для меня выглядит очень трудно читаемым и неструктурным по сравнению с bash. но спасибо. alias сделаю:-)

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

я совсем не знаю питон и он для меня выглядит очень трудно читаемым и неструктурным по сравнению с bash.

Пробовал проходить http://www.codecademy.com/tracks/python ? Так сказать, в игровой форме не напрягаясь за неделю можно изучить начальный синтаксис языка. Мне понравилось, что там всё разбито на маленькие шажки и сразу видно результат, какая команда как работает.

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

Не видел, но ссылку обязательно посмотрю, благодарю.

meklon
() автор топика
Ответ на: комментарий от shell-script
#!/bin/bash
for FileList in *; do
  if [ -f "$FileList" ]; then #проверяем, что сортируемый объект это файл
  #оцениваем время последней модификации файла, со временем создания тупняк почему-то
    FileCreationDate=$(stat $FileList -c %y | awk '{print $1}') 
  fi
  echo $FileCreationDate
  if [ ! -d "$FileCreationDate" ]; then #проверяем отсутствие директории с текущей датой
    mkdir "$FileCreationDate" #создаем директорию соответственно дате
    cp "$FileList" "$FileCreationDate"
  else
    cp "$FileList" "$FileCreationDate"
  fi
done

Вроде все работает. Отсортировал. Буду рад комментариям. Кстати, надо бы корректно как-то добавить условие, чтобы сам скрипт не содавал папки и не падал туда. Если конечно не через alias запускается, а просто лежит в папке, где сортируются файлы.

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

UPD fi перенес вниз, чтобы проверка на то, что объект файл использовалась и при создании папок.

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

Если конечно не через alias запускается, а просто лежит в папке, где сортируются файлы.

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

Кстати, надо бы корректно как-то добавить условие, чтобы сам скрипт не содавал папки и не падал туда.

Тут не понял задачи.

С временем создания не подскажу, не разбирался, но почему-то мне кажется, что это зависит от FS.

shell-script ★★★★★
()
Ответ на: комментарий от meklon

если чуть сократить :

for fileName in `find . -maxdepth 1 -type f `; do
  cdate=$(stat $FileList -c %y $fileName| awk '{print $1}')
  install -D "$fileName" "$cdate/$fileName"
done
и то, сдаётся мне, тут много лишнего

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

Кстати, надо бы корректно как-то добавить условие, чтобы сам скрипт не содавал папки и не падал туда.

Проверяй значение параметра $0 на равенство FileList внутри цикла.

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

Не прокомментируете код? Не понял, если честно.

meklon
() автор топика
Ответ на: комментарий от shell-script

Я ужу добавил в alias как fsort. просто до того я запускал скрипт который лежал в той же папке, что и сортируемые файлы и он сам себя перемещал.

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

Нет, я просто хотел условие вида if объект=файл и объект!=некийфильтр.*; then

вроде через -a добавляется, но не заработало. Если подадите пример множественного условия в данном варианте - буду рад.

meklon
() автор топика
Ответ на: комментарий от shell-script

Еще вопрос. Как реализовать передачу параметров и аргументов скрипту. Я бы реализовал различные варианты сортировки по параметрам. Типа -d как сейчас, -y по годам и т.п. Также по аргументу path можно было бы натравить на конкретную папку, а не на текущую.

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

Как реализовать передачу параметров и аргументов скрипту. Я бы реализовал различные варианты сортировки по параметрам.

Первая ссылка в google

https://www.google.ru/search?q=argc argv bash

$0, $1 и т.д. — это и есть параметры командной строки, которые тебе нужно анализировать. Где $0 — это имя самого скрипта.

#!/bin/sh
echo "Script name [$0]"
scn=$(basename "$0")
for FileList in *; do
  echo "----------"
  if [ -f "$FileList" ]; then #проверяем, что сортируемый объект это файл
  #оцениваем время последней модификации файла, со временем создания тупняк почему-то
    FileCreationDate=$(stat "$FileList" -c %y | awk '{print $1}') 
  fi
  echo $FileCreationDate"/"$FileList
  if [ "x${scn}" = "x${FileList}" ]; then
    echo "Skip"
    continue
  fi
  if [ ! -d "$FileCreationDate" ]; then #проверяем отсутствие директории с текущей датой
    mkdir "$FileCreationDate" #создаем директорию соответственно дате
    echo "mkdir + copying ..."
    cp "$FileList" "$FileCreationDate"
    erx=$?
    if [ $erx -eq 0 ]; then
      echo "ok"
    else
      echo "error = "$erx
    fi
  else
    echo "copying ..."
    cp "$FileList" "$FileCreationDate"
    erx=$?
    if [ $erx -eq 0 ]; then
      echo "ok"
    else
      echo "error = "$erx
    fi
    
  fi
done

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

Вот то же самое на python2

#!/bin/python
import os, shutil
from datetime import datetime

from_dir = "."
to_dir = "."
scn = os.path.basename(__file__)

print "Script name [" + scn + "]"
print "from_dir =", from_dir
print "to_dir =", to_dir

fns = os.listdir(from_dir)
#print fns
for fn in fns:
    st = os.stat(fn)
    #print fn
    #print st
    if os.path.isfile(fn):
        print "-"*40
        t = datetime.fromtimestamp(st.st_mtime)
        #print "variant 1 = " + str(t.year) + "-" + str(t.month).rjust(2, "0") + "-" +  str(t.day).rjust(2, "0")
        #print "variant 2 =", t.strftime("%Y-%m-%d")
        subdir = t.strftime("%Y-%m-%d")
        print os.path.join(from_dir, fn), "-->", os.path.join(to_dir, subdir, fn)

        # Check filenames
        if fn == scn:
            print "Skip"
        else:
            try:
                os.mkdir(os.path.join(to_dir, subdir))
                print "make new dir"
            except:
                pass

            print "copying", st.st_size, "bytes ..."
            
            try:
                shutil.copy2( os.path.join(from_dir, fn), os.path.join(to_dir, subdir, fn))
                print "ok"
            except:
                print "FIXME: Error. Make something with it. Maybe start nuclear attack to Pentagon."
                #raise

justAmoment ★★★★★
()
Ответ на: Вот то же самое на python2 от justAmoment

обработка ошибок шикарная:-) Спасибо за помощь, буду изучать. мой вариант кстати на файлах с пробелами вылетает, хотя вроде все с экранированием.

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