Задача такая - имеется один скрипт, который постоянно складывает файлы в каталог kat1. Второй скрипт должен постоянно брать случайный файл из kat1, обрабатывать его (sed'ом) и скидывать обработанную версию файла в другой каталог kat2.
Возник вопрос: какая конструкция может быстро получать имя случайного файла в каталоге.
find здесь наверно не пойдет, потому что файлы постоянно добавляются новые файлы...
Самый быстрый способ выборки случайного файла из директории
Возник вопрос: какая конструкция может быстро получать имя случайного файла в каталоге.
#!/bin/sh
array=($(ls))
len=${#array[*]}
rand=$[ $RANDOM % $len ]
echo ${array[$rand]}xxblx, ого. Спасибо конечно за вариант, но как-то слишком в лоб мне кажется. Мне кажется это будет тормозить весь процесс...
Может тогда уже лучше что-то типа:
find . -maxdepth 1 -mmin -10|shuf -n1|cut -f2 -d"/"здесь
find . -maxdepth 1 -mmin -10 - найдет все файлы в текущем каталоге, измененные за последние 10 мин.
shuf -n1 - выбор случайной строки-файла
cut -f2 -d"/" - вырезаем имя, так как find возвращает файлы в формате ./file
И то я за find переживаю, даст ли ускорение в плане поиска ключ -mmin? Может есть еще что быстрее?
Или тогда уже через ls, то тогда уже
ls|shuf -n1Хоть не надо строить никакой массив.
Вот что быстрее будет ls или find с ограничением по ключу -mmin?
но как-то слишком в лоб мне кажется.
вопрос был поставлен так: "какая конструкция может быстро получать имя случайного файла в каталоге." - на него я и дал ответ в силу своих знаний (а они у меня невелики). а дальше уж сам смотри подходит он тебе или нет.
Вот что быстрее будет ls или find с ограничением по ключу -mmin?
сделай сначала
time find . -maxdepth 1 -mmin -10|shuf -n1|cut -f2 -d"/"а потом
time ls|shuf -n1и сравни результаты ;)
вопрос был поставлен так: "какая конструкция может быстро получать имя случайного файла в каталоге."
Да. Возможно мне надо было четче уточнить, что ключевое здесь "быстро", так как методов и так понятно что много. В первую очередь я ожидал что может даже есть какая-то утилитка малоизвестная которая выдает имя случайного файла в каталоге и работает скажем как-то системными вызовами из-за чего очень быстро...
Да, я же поблагодарил. Еще раз спасибо ))на него я и дал ответ
По поводу быстродействия - find намного быстрее таки:
valet@valet-comp:/files$ ls |wc -l
1138276
valet@valet-comp:/files$ time find . -maxdepth 1 -mmin -10|shuf -n1|cut -f2 -d"/"
real 0m1.781s
user 0m0.348s
sys 0m1.432s
valet@valet-comp:/files$ time ls|shuf -n1
temp-1358240990.html
real 0m6.643s
user 0m6.136s
sys 0m0.572s
По поводу быстродействия - find намного быстрее таки:
Я бы по два-три раза подряд повторил тест на скорость, тк при первом поиске наверняка читалось с диска, а при втором уже из кэша.
А если Python попробовать?
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from os import listdir
from random import choice
print choice(listdir('.'))
Это фантастика, на каталоге в миллион файлов Python показывает скорость в 5 раз выше find'а. Всунул ваш срипт в testperl:А если Python попробовать?
valet@valet-comp:~/home$ ls files|wc -l
1138276
valet@valet-comp:~/home$ time find files -maxdepth 1 -mmin -10|shuf -n1|cut -f2 -d"/"
real 0m3.428s
user 0m0.348s
sys 0m2.716s
valet@valet-comp:~/home$ time ./testperl
temp-1358312639.html
real 0m0.737s
user 0m0.156s
sys 0m0.556s
valet@valet-comp:~/home$
В чем секрет, откуда такая скорость у питона? Он что как-то принципиально по-другому работает с файловой системой или диском?
Скорее всего, Python скрипт не быстрее find, но быстрее цепочки пайпов.
ЗЫ. И да, тест повторяли несколько раз для чистоты эксперимента?
Да, конечно, время менялось, но менялось там и там, и каждый раз питон был в ~6раз быстрее, чем конструкция с find.ЗЫ. И да, тест повторяли несколько раз для чистоты эксперимента?
Может быть, но почему тогда он быстрее чемСкорее всего, Python скрипт не быстрее find, но быстрее цепочки пайпов.
ls|shuf -n1Может быть, но почему тогда он быстрее чем ls|shuf -n1
в порядке затрат времени:
1) ls сортирует по алфавиту
2) тормоза в трубе
3) накладные расходы на exec() и подгрузку либ
valet@valet-comp:/files$ time find . -maxdepth 1 -mmin -10|shuf -n1|cut -f2 -d"/"
правильно было бы измерять так: time bash -c 'find . -maxdepth 1 -mmin -10|shuf -n1|cut -f2 -d"/"'
иначе относительно правильным будет только real-время
ЗЫ: если большинство файлов относительно новые, то mmin будет сильно тормозить...
А я на него и смотрел ))иначе относительно правильным будет только real-время
не заметил подобного.ЗЫ: если большинство файлов относительно новые, то mmin будет сильно тормозить...
не заметил подобного.
в 2,5 раза разница:
alexander@goblin /tmp/tst $ time find /tmp/tst/ -maxdepth 1 >/dev/null
real 0m0.393s
user 0m0.219s
sys 0m0.172s
alexander@goblin /tmp/tst $ time find /tmp/tst/ -maxdepth 1 -mmin 1000 >/dev/null
real 0m1.070s
user 0m0.184s
sys 0m0.882s
alexander@goblin /tmp/tst $ find /tmp/tst/ -maxdepth 1 |wc -l
940212
и это в tmpfs всё... на железках разница будет несколько меньше, но всё равно существенна:
alexander@goblin ~/tst $ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
alexander@goblin ~/tst $ time find . -maxdepth 1 >/dev/null
real 0m39.109s
user 0m0.235s
sys 0m0.456s
alexander@goblin ~/tst $ time find . -maxdepth 1 >/dev/null
real 0m0.495s
user 0m0.213s
sys 0m0.280s
alexander@goblin ~/tst $ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
alexander@goblin ~/tst $ time find . -maxdepth 1 -mmin 1000 >/dev/null
real 0m56.808s
user 0m0.373s
sys 0m4.153s
alexander@goblin ~/tst $ time find . -maxdepth 1 -mmin 1000 >/dev/null
real 0m1.100s
user 0m0.194s
sys 0m0.902s
alexander@goblin ~/tst $ find . -maxdepth 1 |wc -l
940213
кстати без кеша разница с питоном минимальная, а с кешами меньше, чем в 1,5 раза...
alexander@goblin ~/tst $ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
alexander@goblin ~/tst $ time bash -c "find . -maxdepth 1 | shuf -n1"
./692426270
real 0m30.249s
user 0m0.274s
sys 0m0.519s
alexander@goblin ~/tst $ time bash -c "find . -maxdepth 1 | shuf -n1"
./30414668106
real 0m0.521s
user 0m0.227s
sys 0m0.304s
alexander@goblin ~/tst $ echo 3 | sudo tee /proc/sys/vm/drop_caches
3
alexander@goblin ~/tst $ time ./my.py
15321712054
real 0m29.831s
user 0m0.088s
sys 0m0.477s
alexander@goblin ~/tst $ time ./my.py
19621382664
real 0m0.318s
user 0m0.087s
sys 0m0.229s
То есть делаем выводы, что как не крути - Питон быстрее ))
Это кстати все равно интересно ))
То есть делаем выводы, что как не крути - Питон быстрее ))
Это кстати все равно интересно ))
и на перловке наверняка быстрее получится, а на си ещё быстрее...
но если весь код на баше, то к таким ухищрениям надо прибегать только если скорость неудовлетворительно и доказано, что узкое место именно здесь... перфекционизм совершенно излишен...
кстати ls -f показывает себя лучше find'а...
еще бы примерчик был бы в самый раз, а вдруг :)и на перловке наверняка быстрее получится
да, именно узкое место вот такая вот выборка случайного файла, дальше идет обработка этого случайного файла sed'ом - и это уже быстро, так как работа с одним конкретным файлом (ну а даже если не быстро - это уже никак не ускорить). Почему надо выбирать именно случайный - дело в том, что каталог постоянно в онлайне пополняется новыми файлами, то есть пройтись по определенному списку никак не получится, приходится постоянно получать с каталога случайный.но если весь код на баше, то к таким ухищрениям надо прибегать только если скорость неудовлетворительно и доказано, что узкое место именно здесь
действительно, протестил, так и есть. Но Python еще быстрее - вот в чем фишка :)кстати ls -f показывает себя лучше find'а...
Еще раз все тесты 2 раза на каталоге в более 1 млн файлов:
Показать
1138276
valet@valet-comp:$:~/data/files/temp$ time ls|shuf -n1
temp-1358284308.html
real 0m6.337s
user 0m5.840s
sys 0m0.556s
valet@valet-comp:$:~/data/files/temp$ time find . -maxdepth 1 -mindepth 1 -type f -mmin -100000|shuf -n1|cut -f2 -d"/"
temp-1358279553.html
real 0m1.954s
user 0m0.568s
sys 0m1.444s
valet@valet-comp:$:~/data/files/temp$ time ls -f|shuf -n1
temp-1358338858.html
real 0m0.887s
user 0m0.488s
sys 0m0.448s
valet@valet-comp:$:~/data/files/temp$ time ../../rand_file_python
temp-1358293655.html
real 0m0.555s
user 0m0.156s
sys 0m0.400s
valet@valet-comp:$:~/data/files/temp$ time ls|shuf -n1
temp-1358275701.html
real 0m7.476s
user 0m6.264s
sys 0m0.560s
valet@valet-comp:$:~/data/files/temp$ time find . -maxdepth 1 -mindepth 1 -type f -mmin -100000|shuf -n1|cut -f2 -d"/"
temp-1358414618.html
real 0m1.906s
user 0m0.516s
sys 0m1.444s
valet@valet-comp:$:~/data/files/temp$ time ls -f|shuf -n1
temp-1358290731.html
real 0m0.878s
user 0m0.428s
sys 0m0.496s
valet@valet-comp:$:~/data/files/temp$ time ../../rand_file_python
temp-1358248393.html
real 0m0.568s
user 0m0.128s
sys 0m0.440s
Кстати как видим я специально для find взял mmin большое, чтобы в критерий попадали заведомо все файлы. Все равно find быстр, намного быстрее обычного ls, правда ls -f уже быстрее find, но python несомненный лидер, как видим, он обыгрывает по скорости обычный ls чуть не в 15 раз и быстрее ls -f в 1.5 раза. Для меня кстати до сих пор загадка почему такое происходит, очевидно питон как-то по другому делает системные вызовы к ФС или диску - не могу точно знать, не силен в таких деталях.
Но для моей задачи этот питон более чем, полезен, поэтому большое спасибо -=Serj=- за наводку.
Чтобы не создавать новую тему, хотелось бы еще кое что спросить...
Вот мой скрипт, который обрабатывает файлы (с помощью sed-скрипта script) с большого каталога html_in (в него постоянно другим скриптом докладываются файлы) и складываются в обработанном виде в другой каталог html_out, удаляя в исходном этот файл:
#!/bin/bash
cd html_in/
while [ `../rand_file_python|wc -l` -gt 0 ]
do
file=`../rand_file_python`
../script $file > ../html_out/$file
rm -f $file
done
cd ../
Выборка случайного файла из каталога происходит питоновским скриптом, предложенном в этой теме rand_file_python:
#!/usr/bin/env python
#-*- coding: utf-8 -*-
from os import listdir
from random import choice
print choice(listdir('.'))
Но мне в моем скрипте не нравится то, что приходится 2 раза вызывать выборку случайного файла: один раз для while для проверки условия продолжения обработки цикла, второй раз уже непосредственно для получения случайного файла.
Кто подскажет как это правильно обойти? Думаю можно как-то обойтись одним вызовом с присовением в переменную, но как это правильно сделать в условии обхода цикла?
П.С. Гугление по сабжу "bash while переменная в условии" ничего мне не подсказало, видать не правильно гуглю ))
Использовать что-то, вроде
while True
do
file = `../rand_file_python`
if file не существует
then break
script
done
Это можно, но тогда лишней будет конструкция if file не существует, хотя может это уже попроще будет - все таки не выборка случайного файла.if file не существует
Попробую пока так...
но тогда лишней будет конструкция if file не существует
так она уже итак присутствует:
`../rand_file_python|wc -l` -gt 0