Я действительно думал об одной ситуации, в которой что-то как Щенок Linux будет довольно безопасен (или таким образом, я буду думать - я приветствую комментарии.) При выполнении его с Живого CD в системе без монтируемых устройств хранения (что не означает жесткого диска в системе или по крайней мере не того, который Вы когда-либо используете), затем даже при посещении веб-сайта, который использует некоторую дыру в неисправленном браузере, в следующий раз, Вы перезагружаете свою систему, будет чистым.* Конечно, между временем при посещении такого веб-сайта и перезагрузки мог быть некоторый клавиатурный перехватчик, ловя любые пароли, которые Вы вводите, таким образом, необходимо было бы быть осторожными, возможно, только посетив отмеченные веб-сайты, если Вы не планировали войти в систему где угодно. Вы могли сохранить файлы на карте флэш-памяти с интерфейсом USB, хотя снова необходимо будет быть осторожными, о каком просмотре веб-страниц Вы сделали, в то время как он был соединен (или прежде чем он был соединен).
*Я читал о вирусах (хотя к счастью они, как предполагается, редки), который может заразить Ваш BIOS или некоторую другую часть встроенного микропрограммного обеспечения, и если бы это произошло затем, то перезагрузка не помогла бы.
1.
Первый:
for f in *; do echo "$f" done
сбои для названных файлов -n
, -e
и варианты как -nene
и с некоторым развертыванием удара, с именами файлов, содержащими обратные косые черты.
Второе:
find * -prune | while read f; do echo "$f" done
сбои еще для большего количества случаев (названные файлы !
, -H
, -name
, (
, имена файлов, которые запускаются или заканчиваются пробелами или содержат символы новой строки...),
Это - оболочка, которая расширяется *
, find
действительно только печатает файлы, которые это получает как аргументы. Вы, возможно, также использовали printf '%s\n'
вместо этого, который как printf
встроено, также избежал бы слишком многих args потенциальная ошибка.
2.
Расширение *
отсортирован, можно сделать его немного быстрее, если Вам не нужна сортировка. В zsh
:
for f (*(oN)) printf '%s\n' $f
или просто:
printf '%s\n' *(oN)
bash
не имеет никакого эквивалента насколько я могу сказать, таким образом, необходимо было бы обратиться к find
.
3.
find . ! -name . -prune ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
(выше использования GNU/BSD -print0
нестандартное расширение).
Это все еще включает порождение находки, управляют и используют медленное while read
цикл, таким образом, это, вероятно, будет медленнее, чем использование for
цикл, если список файлов не огромен.
4.
Кроме того, вопреки подстановочному расширению оболочки, find
сделает a lstat
системный вызов на каждом файле, таким образом, маловероятно, что несортировка компенсирует это.
С GNU/BSD find
, этого можно избежать при помощи их -maxdepth
расширение, которое инициирует оптимизацию, сохраняющую lstat
:
find . -maxdepth 1 ! -name '.*' -print0 |
while IFS= read -rd '' f; do
printf '%s\n' "$f"
done
Поскольку find
начинает производить имена файлов, как только это находит их (за исключением выходной буферизации stdio), где это может быть быстрее, то, если то, что Вы делаете в цикле, является трудоемким, и список имен файлов является больше, чем буфер stdio (4/8 КБ). В этом случае обработка в цикле запустится прежде find
закончил находить все файлы. На GNU и системах FreeBSD, можно использовать stdbuf
заставить это происходить раньше (отключающий stdio буферизующий).
5.
POSIX/стандарт/портативное устройство путь к командам выполнения для каждого файла с find
должен использовать -exec
предикат:
find . ! -name . -prune ! -name '.*' -exec some-cmd {} ';'
В случае echo
хотя, это менее эффективно, чем выполнение цикличного выполнения в оболочке, поскольку оболочка будет иметь встроенную версию echo
в то время как find
должен будет породить новый процесс и выполниться /bin/echo
в нем для каждого файла.
Если необходимо выполнить несколько команд, можно сделать:
find . ! -name . -prune ! -name '.*' -exec cmd1 {} ';' -exec cmd2 {} ';'
Но остерегайтесь этого cmd2
только выполняется если cmd1
успешно.
6.
Канонический способ выполнить сложные команды для каждого файла состоит в том, чтобы назвать оболочку с -exec ... {} +
:
find . ! -name . -prune ! -name '.*' -exec sh -c '
for f do
cmd1 "$f"
cmd2 "$f"
done' sh {} +
То время, мы вернулись к тому, чтобы быть эффективным с echo
так как мы используем sh
встроенный и -exec +
версия мечет икру как немногие sh
как возможный.
7.
В моих тестах на каталоге с 200 000 файлов с краткими названиями на ext4, zsh
один (абзац 2.) является безусловно самым быстрым, сопровождается первым простым for i in *
цикл (хотя, как обычно, bash
намного медленнее, чем другие оболочки для этого).
Я попробовал это на каталоге с 2 259 записями и использовал time
команда.
Вывод time for f in *; do echo "$f"; done
(минус файлы!):
real 0m0.062s
user 0m0.036s
sys 0m0.012s
Вывод time find * -prune | while read f; do echo "$f"; done
(минус файлы!):
real 0m0.131s
user 0m0.056s
sys 0m0.060s
Я несколько раз выполнял каждую команду, чтобы устранить неудачные обращения в кэш. Это предлагает удержать его bash
(поскольку я в...), более быстро, чем использование find
и передача по каналу вывода (к bash
)
Только для полноты, я отбросил канал от find
, с тех пор в Вашем примере, это совершенно избыточно. Вывод просто find * -prune
:
real 0m0.053s
user 0m0.016s
sys 0m0.024s
Кроме того, time echo *
(вывод не является разделенной новой строкой, увы):
real 0m0.009s
user 0m0.008s
sys 0m0.000s
На данном этапе я подозреваю причину echo *
более быстро, это не производит столько новых строк, таким образом, вывод не прокручивает столько же. Давайте протестируем...
time find * -prune | while read f; do echo "$f"; done > /dev/null
урожаи:
real 0m0.109s
user 0m0.076s
sys 0m0.032s
в то время как time find * -prune > /dev/null
урожаи:
real 0m0.027s
user 0m0.008s
sys 0m0.012s
и time for f in *; do echo "$f"; done > /dev/null
урожаи:
real 0m0.040s
user 0m0.036s
sys 0m0.004s
и наконец: time echo * > /dev/null
урожаи:
real 0m0.011s
user 0m0.012s
sys 0m0.000s
Часть изменения может составляться случайными факторами, но это кажется ясным:
for f in *; do ...
медленнее, чем find * -prune
, самостоятельно, но для конструкций выше вовлечения каналов, более быстро. Кроме того, как в стороне, оба подхода, кажется, обрабатывают имена с пробелами очень хорошо.
Править:
Синхронизации для find . -maxdepth 1 > /dev/null
по сравнению с. find * -prune > /dev/null
:
time find . -maxdepth 1 > /dev/null
:
real 0m0.018s
user 0m0.008s
sys 0m0.008s
find * -prune > /dev/null
:
real 0m0.031s
user 0m0.020s
sys 0m0.008s
Так, дополнительное заключение:
find * -prune
медленнее, чем find . -maxdepth 1
- в первом оболочка обрабатывает шарик, затем создавая (большую) командную строку для find
. NB: find . -prune
возвраты просто .
. Больше тестов: time find . -maxdepth 1 -exec echo {} \; >/dev/null
:
real 0m3.389s
user 0m0.040s
sys 0m0.412s
Заключение:
find * -prune | while read f; do echo "$f"; done
имеет избыточный канал - весь канал делает, производит точно что find
выводы самостоятельно. Без канала это было бы просто find * -prune
Канал только избыточен конкретно, потому что вещь с другой стороны канала просто копирует stdin в stdout (по большей части). Это - дорогое нет. Если Вы хотите сделать материал с выводом находки, кроме просто плевать это отступает снова, это отличается.
– Phil
22.10.2013, 11:36
*
. Поскольку BitsOfNix заявил: Я все еще настоятельно рекомендую не использовать *
и .
для find
вместо этого.
– rubo77
22.10.2013, 11:45
find . -prune
быстрее потому что find
будет читать запись каталога дословно, в то время как оболочка будет делать аналогично, потенциально соответствуя против шарика (мог бы оптимизировать для *
), затем создавая большую командную строку для find
.
– Phil
22.10.2013, 11:57
find . -prune
печать только .
в моей системе. Это не делает почти никакой работы вообще. Это нисколько не то же как find * -prune
это показывает все имена в текущем каталоге. Пустое read f
исказит имена файлов с продвижением пробелов.
– Ian D. Allen
22.10.2013, 17:13
find * -prune | while read f; do
echo "$f"
done
бесполезное использование find
- То, что Вы говорите, эффективно "для каждого файла в каталоге (*
), не находите файлы. Кроме того, это не безопасно по нескольким причинам:
-r
опция к read
. Это не проблема с for
цикл.for
цикл.Обработка любого имени файла с find
является трудным, таким образом, необходимо использовать for
опция цикла, когда это возможно, по этой причине одна. Кроме того, запуская внешнюю программу как find
в целом будет медленнее, чем выполнение внутренней команды цикла как for
.
find
-print0
ни xargs
' -0
совместимый POSIX, и Вы не можете вставить произвольные команды sh -c ' ... '
(одинарных кавычек нельзя оставить в одинарных кавычках), таким образом, это не совсем настолько просто.
– l0b0
24.10.2013, 01:54
Но мы - любители вопросов о производительности! Этот запрос на эксперимент делает по крайней мере два предположения, которые делают его не ужасно допустимым.
A. Предположите, что они находят те же файлы …
Ну, они найдут те же файлы сначала, потому что они оба выполняют итерации по тому же шарику, а именно, *
. Но find * -prune | while read f
страдает от нескольких дефектов, которые делают это довольно возможным, что это не найдет все файлы, которые Вы ожидаете:
find
реализации делают, но тем не менее, Вы не должны полагаться на это.find *
может повредиться, когда Вы совершаете нападки ARG_MAX
. for f in *
не будет, потому что ARG_MAX
относится exec
, не builtins.while read f
может порвать с запуском имен файлов и окончанием пробелом, который будет неизолированным. Вы могли преодолеть это с while read
и его параметр по умолчанию REPLY
, но это все еще не поможет Вам когда дело доходит до имен файлов с новыми строками в них.B. echo
. Ничья попытка сделать это только для повторения названия файла. Если Вы хотите это, просто сделайте один из них:
printf '%s\n' *
find . -mindepth 1 -maxdepth 1 # for dotted names, too
Канал к while
цикл здесь создает неявную подоболочку, которая закрывается, когда цикл заканчивается, который мог бы быть неинтуитивным для некоторых.
Для ответа на вопрос вот, результаты в моем каталоге, который имеет 184 файла и каталоги в нем.
$ time bash -c 'for i in {0..1000}; do find * -prune | while read f; do echo "$f"; done >/dev/null; done'
real 0m7.998s
user 0m5.204s
sys 0m2.996s
$ time bash -c 'for i in {0..1000}; do for f in *; do echo "$f"; done >/dev/null; done'
real 0m2.734s
user 0m2.553s
sys 0m0.181s
$ time bash -c 'for i in {0..1000}; do printf '%s\n' * > /dev/null; done'
real 0m1.468s
user 0m1.401s
sys 0m0.067s
$ time bash -c 'for i in {0..1000}; do find . -mindepth 1 -maxdepth 1 >/dev/null; done '
real 0m1.946s
user 0m0.847s
sys 0m0.933s
$ ps ax | grep bash 20784 pts/1 Ss 0:00 -bash 20811 pts/1 R+ 0:00 grep bash $ while true; do while true; do while true; do while true; do while true; do sleep 100; done; done; done; done; done ^Z [1]+ Stopped sleep 100 $ bg [1]+ sleep 100 & $ ps ax | grep bash 20784 pts/1 Ss 0:00 -bash 20924 pts/1 S+ 0:00 grep bash
– Phil
22.10.2013, 21:37
Я пошел бы определенно с находкой, хотя я изменю Вашу находку на просто это:
find . -maxdepth 1 -exec echo {} \;
Мудрая производительность, find
намного быстрее в зависимости от Ваших потребностей, конечно. С чем Вы в настоящее время имеете for
это только отобразит файлы/каталоги в текущем каталоге, но не содержании каталогов. Если Вы используете, находят, что это также покажет содержание подкаталогов.
Я говорю, что находка лучше с тех пор с Вашим for
*
должен будет быть расширен сначала, и я боюсь, что, если у Вас есть каталог с огромной суммой файлов, это могло бы давать ошибочный список аргументов слишком долго. То же идет для find *
Как пример, в одной из систем, которые я в настоящее время использую, существует несколько каталогов с более чем 2 миллионами файлов (<100k каждый):
find *
-bash: /usr/bin/find: Argument list too long
-prune
сделать эти два примера более подобными. и я предпочитаю канал с в то время как, таким образом, легче применить больше команд в цикле
– rubo77
22.10.2013, 10:03
Хорошо для начинающих for
ключевое слово оболочки, встроенное в Bash, в то время как find
отдельный исполняемый файл.
$ type -a for
for is a shell keyword
$ type -a find
find is /usr/bin/find
for
цикл только найдет файлы от globstar символа, когда он расширится, он не рекурсивно вызовет ни в какие каталоги, которые он находит.
Найдите на otherhand, будет также дан список, расширенный globstar, но он рекурсивно найдет все файлы и каталоги ниже этого расширенного списка и передаст каждого по каналу до while
цикл.
Оба они приближаются, мог бы считаться опасным в том смысле, что они не обрабатывают пути или имена файлов, которые содержат пробелы.
Это обо всем, о чем я могу думать стоящий комментария эти 2 подхода.
find *
не будет работать правильно если *
производит маркеры, которые похожи на предикаты, а не пути.
Вы не можете использовать обычное --
аргумент для фиксации этого, потому что --
указывает на конец опций, и опции находки прибывают перед путями.
Для устранения этой проблемы, можно использовать find ./*
вместо этого. Но затем это не производит точно те же строки как for x in *
.
Отметьте это find ./* -prune | while read f ..
на самом деле не использует функциональность сканирования find
. Это - globbing синтаксис ./*
который на самом деле пересекает каталог и генерирует имена. Затем find
программа должна будет работать, по крайней мере, a stat
проверьте каждое из тех имен. У Вас есть издержки запуска программы, и наличие его получают доступ к этим файлам и затем выполнению ввода-вывода для чтения его вывода.
Трудно вообразить, как это могло быть совсем не менее эффективно, чем for x in ./* ...
.
В течение многих лет я использовал этот:-
find . -name 'filename'|xargs grep 'pattern'|more
искать определенные файлы (например, *.txt), которые содержат шаблон, который grep может искать и передать его по каналу в больше так, чтобы он не прокручивал от экрана. Иногда я использую>> канал для записи результатов в другой файл, на который я могу посмотреть позже.
Вот образец результата:-
./Documents/Organ_docos/Rodgerstrio321A/rodgersmylist/2008-August.txt:Message-ID: <A165CE5C-61C5-4794-8651-66F5678ABCBF@usit.net>
./Documents/Organ_docos/Rodgerstrio321A/rodgersmylist/2008-August.txt:In-Reply-To: <A165CE5C-61C5-4794-8651-66F5678ABCBF@usit.net>
./Documents/Organ_docos/Rodgerstrio321A/rodgersmylist/2008-August.txt: <A165CE5C-61C5-4794-8651-66F5678ABCBF@usit.net>
./Documents/Organ_docos/Rodgerstrio321A/rodgersmylist/2008-August.txt: <A165CE5C-61C5-4794-8651-66F5678ABCBF@usit.net>
./Documents/Organ_docos/Rodgerstrio321A/rodgersmylist/2008-August.txt:Message-ID: <448E53556A3F442ABC58203D6281923E@hypermax>
./Documents/Organ_docos/Rodgerstrio321A/rodgersmylist/2011-April.txt:URL: http://mylist.net/private/rodgersorganusers/attachments/20110420/3f
Если все файлы, возвращенные находкой, могут быть обработаны единственной командой (очевидно, не применимый к Вашему примеру эха выше), можно использовать xargs:
find * |xargs some-command
!
в команде находки? – rubo77 17.02.2014, 11:43!
для отрицания.! -name . -prune more...
сделаю-prune
(иmore...
с тех пор-prune
всегда возвращает true) для каждого файла, но.
. Таким образом, это сделаетmore...
на всех файлах в.
, но исключит.
и не будет убывать в подкаталоги.
. Таким образом, это - стандартный эквивалент GNU-mindepth 1 -maxdepth 1
. – Stéphane Chazelas 17.02.2014, 12:04