Ваша проблема состоит в том, что Вы берете оболочку для того, каково это не: язык программирования. Оболочка перед всем интерпретатор командной строки. Сценарии оболочки являются сценариями. Это Вы реализуете логику, алгоритм Вашей проблемы в синтаксисе оболочки, затем Вы идете по неправильной дороге.
Существуют очевидные проблемы в Вашем коде как неупомянутые переменные. Но в целом, это просто чувствует себя ужасным для выполнения такого количества команд (поскольку оболочка является инструментом к командам выполнения, не языки программирования) только для нахождения пропорции символов кроме A и T в файле.
Кроме того, awk использует числа плавающие на 64 бита внутренне. Вы уверены, что Вам нужно больше точности, чем это. Если те числа должны использоваться чем-то, что имеет больше точности, чем которая, разве Вы не можете использовать это что-то, чтобы сделать все это?
Для ответа на вопрос Вы сделали бы:
$ echo 1 3 | awk -vRS= '{("echo scale=300\\;" $1 "/" $2 "|bc -l") | getline; print}'
.3333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333333333333333333333333333333333333333333\
33333333333333333333333333333
Но можно легко видеть, как бессмысленный, который является: awk выполнение оболочки и двух команд для каждой строки входа, чтение их вывода и печать его снова... Даже внешняя оболочка, возможно, сделала столь же хорошее задание с меньшим количеством суеты.
Немного менее глупое для приближения к нему, если бы Вы все еще хотите использовать awk, было бы:
echo 1 3 | awk 'BEGIN{print "scale=300"}{print $1"/"$2}' | bc
То время, только один awk
и один bc
команда.
Для меня довольно очевидно, что Вам нужен реальный язык программирования здесь (жемчуг, рубин, Python приходят на ум). Можно назвать интерпретатор для того языка программирования из сценария оболочки, но только однажды: всего одного вызова должно быть достаточно, чтобы сделать все это.
Я вовсе не убежден в этом, но давайте предположим ради аргумента, что вы можете, если готовы приложить достаточно усилий, разобрать вывод ls
надежно, даже перед лицом "противника" - кого-то, кто знает написанный вами код и намеренно выбирает имена файлов, чтобы сломать его.
Даже если бы вы могли это сделать, это все равно было бы плохой идеей.
Bourne shell - не очень хороший язык. Его не следует использовать для чего-либо сложного, если только чрезвычайная переносимость не важнее любого другого фактора (например, autoconf
).
Я утверждаю, что если вы столкнулись с проблемой, в которой разбор вывода ls
кажется путем наименьшего сопротивления для shell-скрипта, то это верный признак того, что все, что вы делаете, слишком сложно для shell и вам следует переписать все на Perl или Python. Вот ваша последняя программа на Python:
import os, sys
for subdir, dirs, files in os.walk("."):
for f in dirs + files:
ino = os.lstat(os.path.join(subdir, f)).st_ino
sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
Здесь нет никаких проблем с необычными символами в именах файлов - output неоднозначен так же, как неоднозначен вывод ls
, но это не имеет значения в "настоящей" программе (в отличие от демонстрационной, как эта), которая будет использовать результат os.path.join(subdir, f)
напрямую.
Не менее важно и то, что в отличие от того, что вы написали, эта программа будет иметь смысл и через полгода, и ее легко будет модифицировать, когда вам понадобится сделать что-то немного другое. В качестве иллюстрации предположим, что вы обнаружили необходимость исключить dotfiles и резервные копии редактора, и обрабатывать все в алфавитном порядке по имени:
import os, sys
filelist = []
for subdir, dirs, files in os.walk("."):
for f in dirs + files:
if f[0] == '.' or f[-1] == '~': continue
lstat = os.lstat(os.path.join(subdir, f))
filelist.append((f, subdir, lstat.st_ino))
filelist.sort(key = lambda x: x[0])
for f, subdir, ino in filelist:
sys.stdout.write("%d %s %s\n" % (ino, subdir, f))
Мантра здесь [119868]никогда не доверяйте файловой системе пользователя[119869] (эквивалент [119870]никогда не доверяйте вводу пользователя[119871]). Если есть метод, который будет работать всегда, со 100% уверенностью, то это должен быть метод, который вы предпочитаете, даже если [119872]ls[119873] делает то же самое, но с меньшей уверенностью. Я не буду вдаваться в технические подробности, так как они широко освещались в [119874]terdon[119875] и [119876]Patrick[119877]. Я знаю, что из-за рисков использования [119878]ls[119879] в важной (и, возможно, дорогой) сделке, где моя работа/представительство стоит на кону, я предпочитаю любое решение, которое не имеет степени неопределенности, если его можно избежать.
Я знаю, что некоторые люди предпочитают [119880]некоторый риск, а не определенность [119881], но [119882]я подал отчет об ошибке [119883].[119467].
предисловие и обоснование исходного ответа † обновлено 18 мая 2015 г.
mikeserv (ОП) заявил в последнем обновлении своего вопроса: «Я считаю позором , хотя то, что я впервые задал этот вопрос, чтобы указать на источник дезинформации, , и, к сожалению, ответ, получивший наибольшее количество голосов, в значительной степени вводит в заблуждение »
. ]Ну ладно; Я чувствую, что было довольно обидно, что я потратил так много времени, пытаясь понять, как объяснить, что я имею в виду, только чтобы найти , что , когда перечитывал вопрос. Этот вопрос закончился "[порождением] обсуждения, а не ответов" ‡ и в итоге составил ~ 18 КБ текста (только для вопроса, для ясности), что было бы долго даже для сообщения в блоге.
Но StackExchange - это не ваша мыльница и не ваш блог. Однако, по сути, вы использовали его, по крайней мере, как частичку того и другого. Люди в конечном итоге тратили много времени, отвечая на ваши «важные замечания», вместо того, чтобы отвечать на реальные вопросы людей. На этом этапе я буду отмечать вопрос как не подходящий для нашего формата, учитывая, что OP прямо заявил, что это даже не предназначалось для того, чтобы быть вопросом.
На данный момент я не уверен, был ли мой ответ по существу или нет; возможно, нет, но он был направлен на некоторые из ваших вопросов, и, возможно, это может быть полезным ответом для кого-то еще; новички воодушевляются, некоторые из тех "не" превращаются в "иногда делаю", когда вы набираетесь опыта. :)
простите, пожалуйста, оставшиеся неровности; я уже потратил на это слишком много времени ... вместо того, чтобы напрямую цитировать OP (как первоначально предполагалось), я попытаюсь подвести итог и перефразировать.
[в значительной степени переработано из моего исходного ответа]
после рассмотрения, я считаю, что я ошибся -читайте акцент, сделанный OP на вопросах, на которые я отвечал; тем не менее, затронутые вопросы были , и я оставил ответы в основном нетронутыми, поскольку считаю, что они являются точными и касаются вопросов, которые, как я видел, возникали в других контекстах. по поводу советов новичкам.
В исходном сообщении по-разному задавался вопрос, почему в различных статьях даются такие советы, как «Не анализируйте вывод ls
» или «Никогда не анализируйте вывод ls
» и так далее.
Мое предлагаемое решение проблемы состоит в том, что примеры такого рода утверждения являются просто примерами идиомы, сформулированной несколько иначе, в которой абсолютный квантор сочетается с императивом [например, «не [никогда] X »,« [вы должны] всегда Y »,« [никогда не] Z »] для формирования утверждений, предназначенных для использования в качестве общих правил или рекомендаций, особенно когда они даются новичкам в предмете, а не как абсолютные истины, несмотря на кажущуюся форму этих утверждений.
Когда вы начинаете изучать новый предмет, и если у вас нет хорошего понимания того, почему вам может потребоваться что-то еще, рекомендуется просто следовать общепринятым общим правилам без исключения - если только под руководством кто-то более испытал это на себе. С повышением квалификации и опыта вы еще больше сможете определять, когда и применимо ли правило в той или иной конкретной ситуации. Когда вы действительно достигнете значительного уровня опыта, вы, вероятно, в первую очередь поймете доводы, лежащие в основе общего правила, и с этого момента вы сможете начать использовать свое суждение относительно того, применимы ли и на каком уровне причины, лежащие в основе правила, в эта ситуация, а также относительно того, есть ли, возможно, главные опасения.
И тогда эксперт, возможно, решит сделать что-то в нарушение «Правил». Но это не сделало бы их менее «Правилами».
Итак, к обсуждаемой теме: на мой взгляд, только потому, что эксперт может нарушить это правило, не будучи полностью разбитым, я не вижу никакого способа, которым вы могли бы оправдать, говоря новичку, что " иногда «нормально анализировать вывод ls
, потому что: это не . Или, по крайней мере, новичку точно так не поступать.
Вы всегда ставите пешки в центр; в дебюте - одна фигура, один ход; замок при первой же возможности; кони перед слонами; рыцарь на ободе мрачен; и всегда следите за тем, чтобы ваш расчет был доведен до конца! (Упс, извини, устаю, это для шахматного StackExchange.)
Читая статью по теме, которая предназначена для новичков или может быть прочитана ими, вы часто будете видеть такие вещи, как это:
Хотя эти утверждения определенно кажутся констатирующими абсолютные и вневременные правила, это не так;вместо этого это способ сформулировать общие правила [a.k.a. «руководящие принципы», «практические правила», «основы» и т. д.], что, по крайней мере, возможно, является одним из подходящих способов изложить их для начинающих, которые могут читать эти статьи. Однако только потому, что они сформулированы как абсолютные, правила, безусловно, не связывают профессионалов и экспертов [которые, вероятно, были теми, кто суммировал такие правила в первую очередь, как способ фиксировать и передавать знания, полученные при решении повторяющихся вопросы в их конкретном ремесле.]
Эти правила определенно не собираются раскрыть, как эксперт будет решать сложную или нюансированную проблему, в которой, скажем, эти правила конфликтуют друг с другом; или в которых соображения, которые изначально привели к правилу, просто не применимы. Эксперты не боятся (или не должны бояться!) Просто нарушать правила, которые, как им известно, не имеют смысла в конкретной ситуации. Эксперты постоянно сталкиваются с уравновешиванием различных рисков и проблем в своем ремесле и часто должны использовать свое суждение, чтобы выбрать нарушение такого рода правил, балансируя различные факторы и не имея возможности просто полагаться на таблицу правил, которым нужно следовать. Возьмем, к примеру, Goto
: ведутся долгие и повторяющиеся споры о том, вредны ли они. (Да, никогда не используйте gotos.; D)
Странная особенность общих правил, по крайней мере в английском и, как мне кажется, во многих других языках, состоит в том, что они сформулированы в той же форме, что и модальное предложение, но эксперты в поле готовы дать общее правило для ситуации, при этом зная, что они нарушат правило, когда это уместно. Таким образом, очевидно, что эти операторы не должны быть эквивалентными тем же операторам в модальной логике.
Вот почему я говорю, что они должны быть просто идиоматическими. Вместо того, чтобы на самом деле быть ситуацией «никогда» или «всегда», эти правила обычно служат для кодификации общих руководящих принципов, которые, как правило, подходят для широкого круга ситуаций, и которые, когда новички следуют им вслепую, могут привести к далеко идущим последствиям. лучшие результаты, чем у новичка, решившего пойти против них без уважительной причины. Иногда они кодифицируют правила, просто приводящие к некачественным результатам, а не к откровенным неудачам, сопровождающим неправильный выбор при нарушении правил.
Итак, общие правила - это не абсолютные модальные предложения, которые они кажутся на поверхности, но вместо этого они представляют собой сокращенный способ дать правило со стандартным подразумеваемым шаблоном, что-то вроде следующего:
если у вас нет возможности чтобы сказать, что это руководство неверно в конкретном случае, и доказать себе, что вы правы, тогда $ {RULE}
, где, конечно, вы могли бы заменить «никогда не анализировать ls
output» из $ {RULE}. :)
ls
Output? Итак, учитывая все это ...Думаю, совершенно очевидно, что это правило хорошее. Прежде всего, настоящее правило должно пониматься как идиоматическое, как объяснено выше ...
Но, кроме того, дело не только в том, что вы должны хорошо разбираться в сценариях оболочки, чтобы знать, можно ли его нарушить в некоторых случаях. частный случай. Кроме того, требуется столько же навыков, чтобы сказать, что вы ошиблись , когда пытаетесь сломать его во время тестирования! И я уверенно заявляю, что очень большая часть вероятной аудитории таких статей (дающих советы вроде «Не анализируйте вывод ls
!») не могут делать эти вещи , и те, кто обладает такими навыками, скорее всего, поймут, что они выяснят это самостоятельно, и все равно проигнорируют правило.
Но ... только посмотрите на этот вопрос, и как даже люди, которые, вероятно, действительно обладают навыками, думали, что это плохой призыв делать это; и сколько усилий потратил автор вопроса, чтобы добраться до точки текущего лучшего примера! Я гарантирую вам, что в решении такой сложной проблемы 99% людей ошибутся, и это даст потенциально очень плохие результаты! Даже если выбранный метод окажется удачным; пока эта (или другая) идея парсинга ls
не будет принята ИТ-специалистами / разработчиками в целом, выдержит множество испытаний (особенно проверку временем) и, наконец, не сможет перейти к «общей методике» 'статус, вполне вероятно, что многие люди могут попробовать и ошибиться ... с катастрофическими последствиями.
Итак, я повторю еще раз ...что, особенно в этом случае , , что - вот почему « никогда не анализирует ls
output!» это определенно правильный способ сформулировать это.
[ОБНОВЛЕНИЕ 2014-05-18: разъяснена причина ответа (см. Выше) для ответа на комментарий OP; следующее дополнение является ответом на добавления OP к вчерашнему вопросу]
[ОБНОВЛЕНИЕ 2014 -11-10:добавлены заголовки и реорганизован / переработан контент; а также: переформатирование, переформулировка, уточнение и эм ... "краткое уточнение" ... я хотел, чтобы это было просто очисткой, хотя это превратилось в небольшую переработку. Я оставил его в плачевном состоянии, поэтому в основном пытался навести порядок. я действительно чувствовал, что важно оставить первую секцию нетронутой; так что там только два незначительных изменения: лишнее «но» удалено и «то» подчеркнуто.]
† Изначально я задумал это исключительно как пояснение к моему оригиналу; но решил внести другие дополнения после размышлений
‡ см. https://unix.stackexchange.com/tour , чтобы ознакомиться с рекомендациями по сообщениям
Вывод команды ls -q
вообще не является глобальным объектом. Он использует ?
для обозначения «Здесь есть символ, который нельзя отобразить напрямую». В глобусах используется ?
для обозначения «Здесь разрешен любой символ».
У глобусов есть другие специальные символы (как минимум *
и []
, а внутри пары []
их больше). Ни один из них не экранируется с помощью ls -q
.
$ touch x '[x]'
$ ls -1q
[x]
x
Если вы обработаете вывод ls -1q
, там есть набор глобусов и расширите их, вы не только получите x
дважды, но и пропустите [x ]
полностью. Как глобус, он не соответствует себе как строке.
ls -q
предназначена для защиты ваших глаз и / или терминала от сумасшедших персонажей, а не для создания чего-то, что вы можете передать обратно в оболочку.
Причина, по которой люди говорят никогда что-то не делать, не обязательно потому, что это абсолютно точно не может быть сделано правильно. Возможно, мы сможем это сделать, но это может быть более сложным и менее эффективным как по пространству, так и по времени. Например, было бы прекрасно сказать: «Никогда не создавайте большой сервер электронной коммерции на сборке x86».
А теперь перейдем к актуальной проблеме: как вы продемонстрировали, вы можете создать решение, которое анализирует ls и дает правильный результат, поэтому проблема не в правильности.
Это сложнее? Да, но мы можем скрыть это за вспомогательной функцией.
Итак, теперь об эффективности:
Экономия места: ваше решение полагается на uniq
для фильтрации дубликатов, следовательно, мы не можем генерировать результаты лениво. Таким образом, либо O (1)
vs. O (n)
], либо оба имеют O (n)
.
Эффективность по времени: в лучшем случае uniq
использует подход хэш-карты, поэтому у нас все еще есть алгоритм O (n)
в количестве добытых элементов , вероятно хотя это O (n log n)
.
Теперь настоящая проблема: хотя ваш алгоритм все еще выглядит неплохо, я очень осторожно использовал элементы , полученные , а не элементы для n. Потому что это имеет большое значение. Допустим, у вас есть файл \ n \ n
, в результате которого будет отображаться глобус для ??
, поэтому сопоставьте все 2-символьные файлы в листинге. Как ни странно, если у вас есть другой файл \ n \ r
, который также приведет к ??
, а также вернет все 2 символьных файла ... посмотрите, к чему это? Экспоненциальное, а не линейное поведение, безусловно, квалифицируется как «худшее поведение во время выполнения». В этом разница между практическим алгоритмом и тем, о котором вы пишете статьи в теоретических журналах CS.
Все любят примеры, правда? Вот так. Создайте папку под названием «test» и используйте этот скрипт python в том же каталоге, где находится папка.
#!/usr/bin/env python3
import itertools
dir = "test/"
filename_length = 3
options = "\a\b\t\n\v\f\r"
for filename in itertools.product(options, repeat=filename_length):
open(dir + ''.join(filename), "a").close()
Единственное, что это делает, - это генерировать все произведения длиной 3 для 7 символов. Математика средней школы подсказывает нам, что должно быть 343 файла. Что ж, это должно быть очень быстро для печати, так что давайте посмотрим:
time for f in *; do stat --format='%n' "./$f" >/dev/null; done
real 0m0.508s
user 0m0.051s
sys 0m0.480s
Теперь давайте попробуем ваше первое решение, потому что я действительно не могу заставить эту
eval set -- $(ls -1qrR ././ | tr ' ' '?' |
sed -e '\|^\(\.\{,1\}\)/\.\(/.*\):|{' -e \
's//\1\2/;\|/$|!s|.*|&/|;h;s/.*//;b}' -e \
'/..*/!d;G;s/\(.*\)\n\(.*\)/\2\1/' -e \
"s/'/'\\\''/g;s/.*/'&'/;s/?/'[\"?\$IFS\"]'/g" |
uniq)
вещь здесь работать на Linux mint 16 (что, я думаю, говорит о многом. удобство использования этого метода).
В любом случае, поскольку вышеупомянутое в значительной степени фильтрует результат только после того, как он его получил, более раннее решение должно быть по крайней мере таким же быстрым, как и более позднее (в нем нет трюков с индексными дескрипторами, но они ненадежны, поэтому вы откажетесь от правильности) .
Итак, сколько времени займет
time for f in $(ls -1q | tr " " "?") ; do stat --format='%n' "./$f" >/dev/null; done
? Ну, я действительно не знаю, проверка имен файлов 343 ^ 343 занимает некоторое время - я скажу вам после тепловой смерти Вселенной.
Я "не анализирую ls
", потому что:
Имена файлов могут содержать любые символы ASCII, кроме /
и NUL
(0x00
). ls
выводит многосимвольные -представления странных символов. Это должно быть отменено (и отменено ), прежде чем имя файла можно будет передать другой программе.
ls
выводитSPACE
("
" ), NewLine(^J
)и другие символы "управления формой" в именах файлов буквально. При последующей обработке следует соблюдать особую осторожность. Все переменные должны быть заключены в кавычки.
По прошествии определенного времени представление даты ls
изменяется с 3 полей ("mmm dd HH:MM
" )на 1 поле ("yyyy
" ), и все последующие поля перенумерованы.
И, #1 причина НЕ получать информацию о файлах путем "парсинга ls
" :Есть лучший способ!
Команду find
можно использовать для выбора файлов, а с опцией -print0
создать список имен файлов (странных и формировать неповрежденные управляющие символы ), разделенные NUL 0x00
байтами.
Команда xargs
с опцией " -0
" потребляет список разделенных NUL
имен файлов и передает их (снова без изменений )в command
, указанный в команде xargs
. линия. command
может быть даже сценарием bash
.
Команда stat
при наличии списка имен файлов может вывести любую информацию о файле в указанном вами формате.
Прочитать man find xargs stat
.
Чтобы посмеяться, прочтите man ls
и попробуйте понять, как можно гарантировать разборчивость