Сканирование по ответам здесь, все они **, похоже, связаны с использованием массива символов недопустимых имен файлов.
Конечно, это может быть микрооптимизация, но в интересах любого, кто мог бы проверить большое количество значений для действительных имен файлов, стоит отметить, что создание хешета недопустимых символов приведет к о более высокой производительности.
В прошлом я был очень удивлен (шокирован), насколько быстро хешсет (или словарь) превосходит итерирование по списку. С строками это смехотворно малое количество (около 5-7 предметов из памяти). С большинством других простых данных (ссылки на объекты, числа и т. Д.) Магический кроссовер, кажется, составляет около 20 элементов.
В списке Path.InvalidFileNameChars имеется 40 недопустимых символов. Был поиск сегодня, и здесь есть неплохой ориентир на StackOverflow, который показывает, что hashset займет чуть более половины времени для массива / списка для 40 элементов: https://stackoverflow.com/a/10762995/949129
Вот класс-помощник, который я использую для дезинфекции путей. Я забыл, почему у меня появился вариант замены, но он там как милый бонус.
Дополнительный бонусный метод «IsValidLocalPath» тоже:)
(** те, которые 't использовать регулярные выражения)
public static class PathExtensions {private static HashSet & lt; char & gt; _invalidFilenameChars; private static HashSet & lt; char & gt; InvalidFilenameChars {get {return _invalidFilenameChars ?? (_invalidFilenameChars = new HashSet & lt; char & gt; (Path.GetInvalidFileNameChars ())); }} /// & lt; summary & gt; Заменяет символы в & lt; c & gt; text & lt; / c & gt; которые недопустимы в именах файлов с указанным символом замены ///. & lt; / summary & gt; /// & lt; param name = "text" & gt; Текст, чтобы ввести действительное имя файла. Эта же строка возвращается, если /// она уже действительна. & Lt; / param & gt; /// & lt; param name = "replacement" & gt; Заменяющий символ или NULL для удаления плохих символов. & lt; / param & gt; /// & lt; param name = "fancyReplacements" & gt; TRUE для замены кавычек и косых черт с символами, отличными от ASCII "и /. & lt; / param & gt; /// & lt; returns & gt; Строка, которая может использоваться как имя файла. Если выходная строка в противном случае была бы пустой, возвращается «_». & Lt; / returns & gt; public static string ToValidFilename (этот текст строки, char? replacement = '_', bool fancyReplacements = false) {StringBuilder sb = new StringBuilder (text.Length); HashSet & л; символ & GT; invalids = InvalidFilenameChars; bool changed = false; for (int i = 0; i & lt; text.Length; i ++) {char c = text [i]; if (invalids.Contains (c)) {changed = true; char repl = replacement ?? '\ 0'; if (fancyReplacements) {if (c == '"') repl = '"'; // U + 201D правая двойная кавычка else if (c == '\' ') repl =' ''; // U + 2019 правая одинарная кавычка else if (c == '/') repl = '/'; // U + 2044 fraction slash} if (repl! = '\ 0') sb.Append (repl);} else sb. Append (c);} if (sb.Length == 0) return "_"; return changed? Sb.ToString (): text;} /// & lt; summary & gt; /// Возвращает TRUE, если указанный путь является действительный локальный путь файловой системы /// & lt; / summary & gt; /// & lt; param name = "pathString" & gt; & lt; / param & gt; /// & lt; возвращает & gt; & lt; / returns & gt; public static bool IsValidLocalPath (это string pathString) {// Из решения на https://stackoverflow.com/a/11636052/949129 Uri pathUri; Boolean isValidUri = Uri.TryCreate (pathString, UriKind.Absolute, out pathUri); return isValidUri & amp; & amp; pathUri! = null & amp; pathUri.IsLoopback;}}
Я подозреваю, что отсутствие новой строки в последней строке вашего файла может вызвать эту проблему. Для тестирования вы можете внести незначительные изменения в свой скрипт и прочитать DATAFILE следующим образом:
while read line
do
echo $line # do processing here
done < "$DATAFILE"
И посмотрите, не имеет значения.
Как обходной путь, перед чтением из текстового файла в файл может быть добавлена новая строка.
echo "\n" >> $file_path
Это обеспечит чтение всех строк, которые были ранее в файле.
Используйте sed для соответствия последней строке файла, который затем добавит новую строку, если она не существует, и пусть она выполняет встроенную замену файла:
sed -i '' -e '$a\' file
Код из этой ссылки stackexchange
Примечание: я добавил пустые одинарные кавычки в -i ''
, потому что, по крайней мере, в OS X, -i
использовал -e
в качестве расширения файла для файла резервной копии. Я бы с радостью прокомментировал исходный пост, но мне не хватило 50 баллов. Возможно, это принесет мне немного в этой теме, спасибо.
read
, потому что он работал отлично 30 лет назад и до сих пор делает для меня. Современный стиль заключается в использовании read -r
, потому что read
был запутан процессом POSIX. Ваш звонок. Я не буду обижаться, если вы используете read -r
, если вы можете объяснить, что он защищает вас, по сравнению с использованием read
, и вы можете объяснить, почему вы заботитесь об этой защите.
– Jonathan Leffler
29 August 2015 в 18:10
Я проверил это в командной строке
# create dummy file. last line doesn't end with newline
printf "%i\n%i\nNo-newline-here" >testing
Протестируйте вашу первую форму (трубопровод к while-loop)
cat testing | while read line; do echo $line; done
Это пропустит последнюю строку, что имеет смысл поскольку read
получает только вход, который заканчивается символом новой строки.
Тест со второй формой (подстановка команды)
for line in `cat testbed1` ; do echo $line; done
Это также возвращает последнюю строку
read
получает вход только в том случае, если он завершен символом новой строки, поэтому вы пропустите последнюю строку.
С другой стороны, во второй форме
`cat testing`
расширяется до формы
line1\nline2\n...lineM
, которая разделяется оболочкой на несколько полей с использованием IFS, поэтому вы получаете
line1 line2 line3 ... lineM
Вот почему вы все равно получаете последнюю строку .
p / s: Я не понимаю, как вы получаете первую форму работы ...
Согласно спецификации POSIX для команды чтения , она должна вернуть ненулевой статус, если «обнаружен конец файла или произошла ошибка». Поскольку EOF обнаружен, когда он читает последнюю «строку», он устанавливает $ line, а затем возвращает статус ошибки, а статус ошибки предотвращает выполнение цикла на этой последней строке. Решение легко: сделайте цикл выполненным, если команда чтения выполнена успешно ИЛИ, если что-то было прочитано в строке $.
while read line || [ -n "$line" ]; do
y
, я побежал: while read line; do echo $line; done < y; echo $line
и получил четыре разных значения. Я не уверен, что это особенно полезное или интуитивное поведение, но ...
– Jonathan Leffler
16 October 2012 в 18:04
У меня была аналогичная проблема. Я делал кошку файла, соединяя его в сортировку и затем передавая результат в «while read var1 var2 var3». т.е.: cat $ FILE | sort -k3 | при чтении Count IP Name do Работа под «do» была оператором if, который идентифицировал изменение данных в поле $ Name и основан на изменении или без изменений составили суммы в $ Count или распечатали суммированную строку отчета. Я также столкнулся с проблемой, когда я не смог получить последнюю строку для печати в отчете. Я пошел с простой возможностью перенаправить cat / sort в новый файл, повторив новую строку для этого нового файла, и THEN запустил мое «пока прочитанное количество IP-адресов» в новом файле с успешными результатами. ie: cat $ FILE | sort -k3> NEWFILE echo "\n" >> NEWFILE cat NEWFILE | при чтении Count IP Name do Иногда простой, неэлегантный - лучший способ пойти.