Нужна помощь в написании скрипта.

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

k0rven
Сообщения: 13
ОС: Debian

Нужна помощь в написании скрипта.

Сообщение k0rven »

Привет всем!
Нужна помощь опытных и бывалых :)

Условие:

Есть каталоги /home/vova/out/ и /home/goga/out/, нужен скрипт, котрый бы проверял каталог /home/vova/out/ на наличие в нем файлов (любых, скрытые не нужны) и перемещал бы их в /home/goga/out/. В дальнейшем этот скрипт планирется запускать cron-ом каждые 15 минут.
Спасибо всем заранее :)
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: Нужна помощь в написании скрипта.

Сообщение sash-kan »

$ rsync -a /home/vova/out/ /home/goga/out/

слэши в конце не забудьте (хотя бы в конце первого аргумента)·

k0rven писал(а):
12.04.2012 15:07
перемещал
пропустил это слово·
удалять после копирования обязательно?
тогда добавьте после rsync вторую команду:
$ rm -rf /home/vova/out/*
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

Зачем тут rsync то? Прям из пушки по воробьям (:

Код: Выделить всё

find /home/vova/out/ -type f -not -name ".*" -exec echo mv {} /home/goga/out/ \;

или

Код: Выделить всё

for i in /home/vova/out/* ; do mv "$i" /home/goga/out/ ; done
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
bormant
Сообщения: 1354

Re: Нужна помощь в написании скрипта.

Сообщение bormant »

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

А зачем for, если /home/vova/out/* уже способно дать длинный список, чем это принципиально отличается от тривиального

Код: Выделить всё

(cd /home/vova/out/; mv -t /home/goga/out/ *)

Переход в каталог использован для сокращения командной строки после глоббинга, -t для исключения "вылета" каталога назначения за пределы списка.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

bormant писал(а):
12.04.2012 18:29
find понимаю зачем -- если количество файлов велико для командной строки.

А зачем for, если /home/vova/out/* уже способно дать длинный список, чем это принципиально отличается от тривиального

Код: Выделить всё

(cd /home/vova/out/; mv -t /home/goga/out/ *)

Переход в каталог использован для сокращения командной строки после глоббинга, -t для исключения "вылета" каталога назначения за пределы списка.

Может для того же, для чего и find - если к-во файлов больше максимально допустимого для командной строки? Ведь к-во аргументов после 'for in' не ограничено (по крайней мере, к-вом аргументов командной строки).
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

bormant писал(а):
12.04.2012 18:29

Код: Выделить всё

(cd /home/vova/out/; mv -t /home/goga/out/ *)
Собственно, есть 2 причины не использовать данную конструкцию:
1. Слишком много файлов приведут к ошибке, что аргументов много.
2. Отсутствие файлов для перемещения тоже приведёт к ошибке, что, мол mv: cannot stat `*': No such file or directory.
Всё это будет приводить к тому, что cron будет усиленно слать сообщения о каких-то проблемах во время отработки задания по мылу руту или администратору, в зависимости от настроек сервера. А это не есть хорошо.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

SLEDopit, кстати, я тут подумал: а почему вы выбрали '-exec {} \;' , а не '-exec {} \+' для find-а ?

Upd. Да, и еще кстати: ваш вариант с for будет копировать скрытые файлы в подпапках, которые, видимо, не нужны.
Upp2. А вариант с find пропустит все симлинки. Хоть автор темы ничего про них и не написал, но, мне кажется, из-за этого вполне может что-то поломаться.
Upd3. А еще я не уверен, сможет ли он сохранить хардлинки или понаделает вместо них разные файлы.. :huh:
Спасибо сказали:
Аватара пользователя
bormant
Сообщения: 1354

Re: Нужна помощь в написании скрипта.

Сообщение bormant »

sgfault писал(а):
12.04.2012 18:43
к-во аргументов после 'for in' не ограничено (по крайней мере, к-вом аргументов командной строки).
Собственно, остался вопрос про источник подобного утверждения, это где-то документировано?

Если бы речь шла не про "for var in ...", а про что-то вроде

Код: Выделить всё

ls -1 /home/vova/out/ | while read file; do ...
то полностью согласен, тут ограничения нет, ибо список в пайпе, а не в строке.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

bormant писал(а):
12.04.2012 19:17
Собственно, остался вопрос про источник подобного утверждения, это где-то документировано?
Дело в том, что в системе есть ограничение на количество аргументов для нового процесса (именно это и происходит при попытке запуска rm, mv, etc). А при запуске for / echo / etc builtin новый процесс не создаётся => ограничения упирается в память.
Узнать ограничение на количество аргументов можно так:

Код: Выделить всё

getconf ARG_MAX

Увы, ткнуть носом, где конкретно это написано, не могу, т.к. запамятовал.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
k0rven
Сообщения: 13
ОС: Debian

Re: Нужна помощь в написании скрипта.

Сообщение k0rven »

Всем принимавшим участие спасибо, пока испытал только
for i in /home/vova/out/* ; do mv "$i" /home/goga/out/ ; done - работает на ура, завтра протестирую кроном, отпишусь
вы брал самую короткую - остальные не проверял. спасибо SLEDopit, откуда такие глубокие познания? Могли бы вы разъяснить популярно что именно делает эта конструкция. - я просто не силен в скриптинге.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

bormant писал(а):
12.04.2012 19:17
sgfault писал(а):
12.04.2012 18:43
к-во аргументов после 'for in' не ограничено (по крайней мере, к-вом аргументов командной строки).
Собственно, остался вопрос про источник подобного утверждения, это где-то документировано?

for - ключевое слово языка, а не программа. Ограничение, если и есть, не имеет никакого отношения к количеству аргументов командной строки, тк никакого вызова другой программы здесь не происходит - просто какие-то действия выполняются интерпретатором (самой оболочкой). Если объяснение "for - ключевое слово языка" вас не устраивает, то могу предложить только результат эксперимента:

Код: Выделить всё

$ mkdir t
$ cd t
$ seq 1 1000000 | xargs touch
$ find | wc -l
1000001
$ ls *
bash: /bin/ls: Argument list too long
$ ( for i in *; do echo "$i"; done ) | wc -l
1000000


SLEDopit писал(а):
12.04.2012 19:33
Узнать ограничение на количество аргументов можно так:

Код: Выделить всё

getconf ARG_MAX

Не уверен, что это будет именно количество. Эксперимент выше показывает, что 1000000 аргументов слишком много, хотя значение ARG_MAX у меня:

Код: Выделить всё

$ getconf ARG_MAX
2097152

Кроме того, sysconf(3) все-таки говорит про максимальную длину, а не количество:
ARG_MAX - _SC_ARG_MAX
The maximum length of the arguments to the exec(3) family of functions. Must not be less than _POSIX_ARG_MAX (4096).

Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Нужна помощь в написании скрипта.

Сообщение drBatty »

я всетаки не понял, чем вариант с rsync не понравился? Она и удалять умеет и файлы .* пропустит.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
k0rven
Сообщения: 13
ОС: Debian

Re: Нужна помощь в написании скрипта.

Сообщение k0rven »

drBatty писал(а):
13.04.2012 07:19
я всетаки не понял, чем вариант с rsync не понравился? Она и удалять умеет и файлы .* пропустит.


вариант с rsync-ом не перемещал файлы в нужную директорию, может здесь он неверны я к сожалению не разобрался. Долго копал в этом напрпавлении думаю самый верный предложенный выше я уже писал, еще пробовал использовать конструкцию типа if test -e /home/vova/* || mv ...
но тоже как то не проканало.
Спасибо сказали:
Аватара пользователя
sash-kan
Администратор
Сообщения: 13939
Статус: oel ngati kameie
ОС: GNU

Re: Нужна помощь в написании скрипта.

Сообщение sash-kan »

k0rven писал(а):
13.04.2012 08:46
вариант с rsync-ом не перемещал файлы в нужную директорию
про удаление файлов после копирования rsync-ом я написал в первом своём посте·
Писать безграмотно - значит посягать на время людей, к которым мы адресуемся, а потому совершенно недопустимо в правильно организованном обществе. © Щерба Л. В., 1957
при сбоях форума см.блог
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Нужна помощь в написании скрипта.

Сообщение drBatty »

sgfault писал(а):
12.04.2012 18:43
Ведь к-во аргументов после 'for in' не ограничено (по крайней мере, к-вом аргументов командной строки).

да ладно! for in тут вообще не причём, тут работает глоббинг звёздочки - звёздочка заменяется на строку, в которой перечислены и отсортированы все файлы кроме скрытых в текущем каталоге.
k0rven писал(а):
13.04.2012 08:46
вариант с rsync-ом не перемещал файлы в нужную директорию

перемещение == копирование + удаление (в общем случае)
sash-kan писал(а):
13.04.2012 10:44
про удаление файлов после копирования rsync-ом я написал в первом своём посте·

неправильно написали - а если что-то случится? ваша rm -rf всё напрочь поудаляет. Удалять нужно только после _успешного_ копирования.
т.е. rsync ... && rm -f src_dir/*
Хотя, как я понял ТСа, ему нужны только файлы, потому лучше ИМХО сделать так:

$

find source_dir -maxdepth 1 -type f -exec mv -t target_dir {} +

http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21433
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в написании скрипта.

Сообщение Bizdelnick »

drBatty писал(а):
13.04.2012 12:01
перемещение == копирование + удаление (в общем случае)

Тут скорее всего не общий, а частный случай, когда перемещение выполняется в пределах одной ФС.
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

drBatty писал(а):
13.04.2012 12:01
sgfault писал(а):
12.04.2012 18:43
Ведь к-во аргументов после 'for in' не ограничено (по крайней мере, к-вом аргументов командной строки).

да ладно! for in тут вообще не причём, тут работает глоббинг звёздочки - звёздочка заменяется на строку, в которой перечислены и отсортированы все файлы кроме скрытых в текущем каталоге.

Вообще не понял, какое отношение ваша фраза имеет к моей :unsure: Я писал про возможное ограничение на к-во word-ов (я их назвал "аргументами") в конструкции for in (если оно вообще есть), а вы почему-то про само выражение после in. Какое вообще отношение выражение после in имеет к ограничению на к-во word-ов? Или что, может, если я напишу там что-то другое, например $(seq 1 1000000), то это ограничение изменится?
Так что это как раз звездочка тут совсем не при чем.
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5456
ОС: Gentoo

Re: Нужна помощь в написании скрипта.

Сообщение /dev/random »

drBatty писал(а):
13.04.2012 12:01
да ладно! for in тут вообще не причём, тут работает глоббинг звёздочки - звёздочка заменяется на строку, в которой перечислены и отсортированы все файлы кроме скрытых в текущем каталоге.

Нет. Не заменяется. Если вы вместо "for in" напишете обычную команду - тогда будет заменяться, со всеми присущими этому варианту недостатками, например, невозможностью отличить пробел-разделитель от пробела внутри имени файла. А "for <переменная> in <шаблон>" - специальная конструкция, которая проходит по всем файлам, соответствующим шаблону, без перевода их списка в строку и без путаницы со спецсимволами в именах файлов. И без ограничения длины, да.

Upd: прошу прощения, ошибся. Не удаляю это сообщение, т.к. на него уже ответили, но не пытайтесь руковотствоваться им.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

/dev/random писал(а):
13.04.2012 13:06
Если вы вместо "for in" напишете обычную команду - тогда будет заменяться, со всеми присущими этому варианту недостатками, например, невозможностью отличить пробел-разделитель от пробела внутри имени файла.

Ээ.. нет, это не может быть так. Вот последовательность, в которой производятся expansion (bash(1)):
There are seven kinds of expansion performed: brace expansion, tilde expansion, parameter and variable expansion,
command substitution, arithmetic expansion, word splitting, and pathname expansion.

Только word splitting может изменить к-во слов, но звездочка заменяется после него. Те на имена файлов, подставленные при pathname expansion, word splitting не оказывает никакого влияния. Вот пример:

Код: Выделить всё

$ cat ./t.sh
#!/bin/bash

for i ; do
    echo "'$i'"
done

$ ll
total 4
-rw-r----- 1 sgf sgf  0 Apr 13 13:17 a  b
-rw-r----- 1 sgf sgf  0 Apr 13 13:17 c
-rwx------ 1 sgf sgf 46 Apr 13 13:19 t.sh
$ ./t.sh *
'a  b'
'c'
't.sh'
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

sgfault писал(а):
13.04.2012 13:24
Ээ.. нет, это не может быть так. Вот последовательность, в которой производятся expansion (bash(1)):
Возможно имелась в виду последующая обработка уже раскрытого списка. Что-нибудь в духе

Код: Выделить всё

for i in $(ls *)
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

SLEDopit писал(а):
13.04.2012 13:29
sgfault писал(а):
13.04.2012 13:24
Ээ.. нет, это не может быть так. Вот последовательность, в которой производятся expansion (bash(1)):
Возможно имелась в виду последующая обработка уже раскрытого списка. Что-нибудь в духе

Код: Выделить всё

for i in $(ls *)


А, ну да, это проблема. Но в таком примере (command substitution без двойных кавычек) проблема будет не только с word splitting, но и pathname expansion. Те, word splitting разобьет имена файлов по символам IFS, а pathname expansion по своим спецсимволам. Те

Код: Выделить всё

$ ll
total 4
-rw-r----- 1 sgf sgf  0 Apr 13 13:34 *
-rw-r----- 1 sgf sgf  0 Apr 13 13:17 a  b
-rw-r----- 1 sgf sgf  0 Apr 13 13:17 c
-rwx------ 1 sgf sgf 46 Apr 13 13:19 t.sh
$ ( for i in $(ls *); do echo "'$i'"; done )
'*'                     <----  это
'a  b'                 <----  результат
'c'                     <----  pathname expansion
't.sh'                 <----  для файла с именем звездочка
'a'           <- а это
'b'           <- результат word splitting для файла с пробелом
'c'
't.sh'

Те использовать такую конструкцию без

Код: Выделить всё

set -f
IFS=$'\xa'  (или IFS='', хотя польза последнего сомнительна)

все равно, что стрелять себе в ногу :huh:
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Нужна помощь в написании скрипта.

Сообщение drBatty »

Bizdelnick писал(а):
13.04.2012 12:35
Тут скорее всего не общий, а частный случай, когда перемещение выполняется в пределах одной ФС.

концептуально это тоже не играет роли - мы сначала копируем _имя_ файла из одного каталога, а потом его удаляем. Технически это конечно атомарная операция, но в принципе это тоже самое копирование+удаление. (:
Т.ч. формально моё формальное определение верно во всех случаях.
sgfault писал(а):
13.04.2012 12:44
1. Какое вообще отношение выражение после in имеет к ограничению на к-во word-ов?
2. Или что, может, если я напишу там что-то другое, например $(seq 1 1000000), то это ограничение изменится?

1. А вот этого я не знаю. ИМХО это зависит от реализации bash'а - если там для раскрытия * используется тот же механизм, что и для раскрытия звёздочки в командной строке, то ограничение есть.
2. нет, не изменится. Однако, 1 000 000 это очень мало, на самом деле. Практика показывает, что bash на современном железе такое легко съедает. А вот во времена первого пня (начало нулевых), bash такое тоже молча съедал, однако обрабатывались не все слова/имена. Я не знаю, как оно сейчас в теории и в стандарте, но предпочитаю так не делать, на всякий случай. Есть ведь xargs, есть плюс для find, они как раз и кормят команды таким количеством файлов, как оно возможно в данной реализации.
/dev/random писал(а):
13.04.2012 13:06
пробел-разделитель от пробела внутри имени файла. А "for <переменная> in <шаблон>" - специальная конструкция, которая проходит по всем файлам, соответствующим шаблону, без перевода их списка в строку и без путаницы со спецсимволами в именах файлов. И без ограничения длины, да.

да? А я вот такого в документации не видел. Может есть более конкретная ссылка? Судя по моему мануалу, for in обрабатывает параметры параметр как список слов, т.е. типа как массив. Причём с сортировкой. Т.е. проблем с пробелами конечно нет, но вот с длинной - я тут не уверен.
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
Bizdelnick
Модератор
Сообщения: 21433
Статус: nulla salus bello
ОС: Debian GNU/Linux

Re: Нужна помощь в написании скрипта.

Сообщение Bizdelnick »

drBatty писал(а):
13.04.2012 14:31
концептуально это тоже не играет роли - мы сначала копируем _имя_ файла из одного каталога, а потом его удаляем. Технически это конечно атомарная операция, но в принципе это тоже самое копирование+удаление. (:
Т.ч. формально моё формальное определение верно во всех случаях.

Не надо разводить демагогию. mv != cp && rm
Пишите правильно:
в консоли
вку́пе (с чем-либо)
в общем
вообще
в течение (часа)
новичок
нюанс
по умолчанию
приемлемо
проблема
пробовать
трафик
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

drBatty писал(а):
13.04.2012 14:31
Технически это конечно атомарная операция, но в принципе это тоже самое копирование+удаление.
Фига се. А я-то ломал ломал голову, что это у меня в пределах одной файловой системы mv 100500GB.file занимает < 1 секунды, а cp && rm 100500GB.file около часа.
k0rven писал(а):
12.04.2012 19:48
SLEDopit, откуда такие глубокие познания?
Глубокие? Да я знаю маленькую толику и познание нового продвигается невероятно медленно. К сожалению.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
k0rven
Сообщения: 13
ОС: Debian

Re: Нужна помощь в написании скрипта.

Сообщение k0rven »

Всего то надо было файлы из папки в др. папку переместить, а столько букв! ;-) АЕще раз спасибо за ответы, правда из всего написанного я так до конца и не понял как именно работает приведенная вами (SLEDopit) конструкция for i in /home/vova/out/* ; do mv "$i" /home/goga/out/ ; done
будьте добры объясните, если не трудно или линканите что почитать, а то ведь хочется самому научиться писать простейшие скрипты.
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

k0rven писал(а):
13.04.2012 15:27
for i in /home/vova/out/* ; do mv "$i" /home/goga/out/ ; done
Это самый обычный цикл for, который для каждого файла, соответствующего маске /home/vova/out/*, запускает команду перемещения её в другую директорию. Подробнее о циклах.
k0rven писал(а):
13.04.2012 15:27
ведь хочется самому научиться писать простейшие скрипты.
учебник.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Нужна помощь в написании скрипта.

Сообщение drBatty »

SLEDopit писал(а):
13.04.2012 14:49
Фига се. А я-то ломал ломал голову, что это у меня в пределах одной файловой системы mv 100500GB.file занимает < 1 секунды, а cp && rm 100500GB.file около часа.

а читать внимательнее надо:
drBatty писал(а):
13.04.2012 14:31
концептуально это тоже не играет роли - мы сначала копируем _имя_ файла из одного каталога, а потом его удаляем.

вы 100500 ИМЁН перемещали? Или ИМЯ одного каталога? Или 100500 ИМЁН + 100500 ДАННЫХ?
SLEDopit писал(а):
13.04.2012 16:12
Это самый обычный цикл for, который для каждого файла, соответствующего маске /home/vova/out/*, запускает команду перемещения её в другую директорию.

согласитесь, что этот способ таки быстрее и лучше: Нужна помощь в написании скрипта.
(:
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4824
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Нужна помощь в написании скрипта.

Сообщение SLEDopit »

drBatty писал(а):
13.04.2012 16:30
вы 100500 ИМЁН перемещали? Или ИМЯ одного каталога? Или 100500 ИМЁН + 100500 ДАННЫХ?
Так в том то и разница, что при mv данные не перемещаются, а при cp && rm - перемещаются (напомню, что речь идёт про действия внутри одной файловой системы). Поэтому принципиальная разница таки есть.
drBatty писал(а):
13.04.2012 16:30
согласитесь, что этот способ таки быстрее и лучше: Нужна помощь в написании скрипта.
Так, так, мы вроде спорили о mv vs rsync, а тут мне уже говорят про find vs mv. Как всё быстро меняется (:
И таки да, при большом количестве файлов find будет заметно быстрее работать.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -

Re: Нужна помощь в написании скрипта.

Сообщение sgfault »

drBatty писал(а):
13.04.2012 14:31
sgfault писал(а):
13.04.2012 12:44
1. Какое вообще отношение выражение после in имеет к ограничению на к-во word-ов?
2. Или что, может, если я напишу там что-то другое, например $(seq 1 1000000), то это ограничение изменится?

1. А вот этого я не знаю. ИМХО это зависит от реализации bash'а - если там для раскрытия * используется тот же механизм, что и для раскрытия звёздочки в командной строке, то ограничение есть.

А вы считаете, что механизм раскрытие звездочки в командой строке отличается от раскрытия звездочки в for? Я утверждаю, что нет. См ниже пояснение.
drBatty писал(а):
13.04.2012 14:31
<..> Есть ведь xargs, есть плюс для find, они как раз и кормят команды таким количеством файлов, как оно возможно в данной реализации.

Зачем тут xargs, если for - не команда, а ключевое слово языка.
Еще раз:
1. bash читает текстовый файл:
mv *
2. и видит simple command, состоящую из двух word.
3. выполняет pathname expansion на втором слове. Это действие, которое выполняет интерпретатор (bash), и результат его хранится где-то в его внутренних структурах данных. Единственное ограничение, которое может быть у размера этого результата - это ограничение внутренних структур данных bash-а (например, размер int-а, если это массив, или еще что-то).
4. собирается выполнять exec(3) и проверяет ARG_MAX (sysconf(3)), и видит, что его структура данных не помещается в ARG_MAX. Тогда он пишет что-то такое:

Код: Выделить всё

bash: /bin/ls: Argument list too long

В случае с for-ом шаги 1-3 аналогичны и отличается только конец:
1. bash читает текстовый файл:
for i in *; do ... done
2. и видит compound command состоящую из.. скольких-то word.
3. применяет pathname expansion на * и записывает результат в свою внутреннюю структуру.
4. запускает какую-то свою функцию, которой передает в качестве аргумента (допустим) указатель на внутреннюю структуру данных, содержащую результат pathname expansion с шага 3. Никакой ARG_MAX не влияет и не может влиять на размер внутренней структуры, по которой "идет" for цикл, тк здесь нету никакого exec(3).

Я не читал исходников bash-а, и не могу дать ни ссылок на ф-ии, ни сказать точно, как это работает. Это описание должно всего лишь объяснить разницу между ключевым словом (reserved word) и запуском внешней команды.

drBatty писал(а):
13.04.2012 16:30
согласитесь, что этот способ таки быстрее и лучше: Нужна помощь в написании скрипта.
(:

А с вашим любимым find-ом, кстати, будет куча проблем с симлинками. Конечно, к вашему варианту это не относится, тк вы предусмотрительно написали '-type f'. Но просто обычно выкидывать симлинки - не самое лучше, чем можно заниматься на АФ что можно придумать. Все-таки.

PS. Ах, да, еще: если вы утверждаете, что в двух описанных выше сценариях обработки bash-ем скрипта используется разная реализация pathname expansion.. :huh: Ну, что ж, я не могу вам доказать обратного, но в моем понимании - это по меньшей мере, крайне странно и нелогично, и, тк я не вижу ни одного основания для такого предположения, то и смотреть исходники не вижу для себя никакого смысла.
Спасибо сказали:
Аватара пользователя
drBatty
Сообщения: 8735
Статус: GPG ID: 4DFBD1D6 дом горит, козёл не видит...
ОС: Slackware-current

Re: Нужна помощь в написании скрипта.

Сообщение drBatty »

SLEDopit писал(а):
13.04.2012 16:44
Так в том то и разница, что при mv данные не перемещаются, а при cp && rm - перемещаются (напомню, что речь идёт про действия внутри одной файловой системы). Поэтому принципиальная разница таки есть.

вопрос в том, что считать данными? Вот вы содержимое каталога данными считаете? А я - считаю. И если внимательно исследовать работу mv, то она чётко распадается на два действия:
1. данные файла (имя и inode) копируются из одного каталога в другой, а точнее - записываются в хвост каталога-приёмника.
2. данные файла удаляются из каталога-источника.
Вполне возможно выполнить только первый пункт, т.е. mv без удаления: для этого служит команда ln. Она создаёт точную копию имени файла (хардлинк). На практике конечно ln+rm не совсем совпадает с mv, но в принципе они эквивалентны.
sgfault писал(а):
13.04.2012 23:35
А вы считаете, что механизм раскрытие звездочки в командой строке отличается от раскрытия звездочки в for? Я утверждаю, что нет.

я тоже считаю, что там один и тот же механизм. И помнится у меня он привёл к печальным последствиям: я автоматически создавал бекап большого числа файлов, и в этот бекап попали не все файлы. Я не знаю, что послужило причиной сбоя, возможно звёздочка раскрылась правильно, но tar не справился с большим объёмом. Факт остаётся фактом: бекап получился битый, ИЧСХ никаких сообщений об ошибке не поступило.
sgfault писал(а):
13.04.2012 23:35
Зачем тут xargs, если for - не команда, а ключевое слово языка.

дело не в for, а в звёздочке:
1. она _может_ раскрыться не полностью, и на практике лично я такое наблюдал.
2. перед звёздочкой надо по уму проверить, не является-ли каталог пустым. Иначе в этой вполне штатной ситуации звёздочка не раскроется, и если она в КС, то сама звёздочка и передастся, а если она в for in *, то передастся пустая строка.

$

for f in *; do echo "i='$i'"; done i='' echo * *


3. поведение звёздочки почти не регулируемое. В частности она не отличает каталоги от файлов, не понимает, что симлинк это не обычный файл, и не видит скрытых файлов.
4. Звёздочка выдаёт не просто список файлов, а отсортированный список. Практически всегда это не нужно. Какой смысл тратить ресурсы на ненужную сортировку? (если каталог большой, то ресурсы не малые, ибо сортировать надо "на месте", а это O(N*log(N)) по времени, и ещё O(N) по памяти).
sgfault писал(а):
13.04.2012 23:35
А с вашим любимым find-ом, кстати, будет куча проблем с симлинками.

вот как раз с find никаких проблем и не будет: есть там опции -P, -L, и -H, которые позволяют мне обрабатывать симлинки именно так, как _мне_ это нужно. А не как звёздочка, которая (не)раскрывается так, как _она_ хочет.
sgfault писал(а):
13.04.2012 23:35
Конечно, к вашему варианту это не относится, тк вы предусмотрительно написали '-type f'. Но просто обычно выкидывать симлинки - не самое лучше, чем можно заниматься на АФ что можно придумать. Все-таки.

ну не нравится такое поведение - поменяйте. К вашему распоряжению кроме упомянутых H,L,P есть ещё xtype & follow. Для звёздочки всего этого нет, и не будет...
sgfault писал(а):
13.04.2012 23:35
Ах, да, еще: если вы утверждаете, что в двух описанных выше сценариях обработки bash-ем скрипта используется разная реализация pathname expansion..

не утверждаю. Думаю одна и та же, только вот работает она иначе (пример выше)
http://emulek.blogspot.ru/ Windows Must Die
Учебник по sed зеркало в github

Скоро придёт
Осень
Спасибо сказали: