У меня часто есть задачи программирования оболочки, где я сталкиваюсь с этим шаблоном:
cat file | some_script > file
Это небезопасно - кошка не могла читать во всем файле, прежде чем some_script начнет писать в него. Я действительно не хочу писать результат во временный файл (его медленное, и я не хочу добавленной сложности продумывания уникального нового имени).
Возможно, существует существует стандартная команда оболочки, которая буферизует целый поток, пока EOF не будет достигнут? Что-то как:
cat file | bufferUntilEOF | script > file
Идеи?
Здесь использование временного файла - правильное решение. Когда вы используете перенаправление типа '>', оно обрабатывается оболочкой, и независимо от того, сколько команд в вашей цепочке, оболочка может удалять и перезаписывать выходной файл перед выполнением любой команды (во время настройки цепочек).
Проходя через различные ответы здесь, и сероголовые соколы обновления и разъяснения, кажется, что то, что хочет asker является класс, который выглядит, пахнет и звучит как Последовательность, но не является.
То есть они хотели бы иметь возможность:
MyString string = "String!!";
Это не может работать, так как java.lang. Последовательность
является конечным классом, и поэтому каждый «Последовательности»
, который создает компилятор, будет объектом java.lang. Последовательность
, так как это не объект MyString
, они не могут быть назначены друг другу.
В слабо набранных языках вы смогли бы создать такой класс, так как если класс выглядит, пахнет и звучит как утка , то по всем замыслам и целям, это утка. Ява, однако, является сильно типизированным языком, а утка - только утка, если это происходит из семейства птиц Anatidae .
-121--3224995- Единственное, что я вижу, это то, что вы получаете доступ к q
одновременно из разных потоков - без блокировки, как вы действительно пишете. Это требует неприятностей - и вы, вероятно, получаете неприятности в виде переводчика Python, запирающегося на вас.:
Попробуйте заблокировать, это действительно не очень сложно:
import sys, time
import xml.parsers.expat
import threading
q = []
q_lock = threading.Lock() <---
def start_handler(name, attrs):
q_lock.acquire() <---
q.append(name)
q_lock.release() <---
def do_expat():
p = xml.parsers.expat.ParserCreate()
p.StartElementHandler = start_handler
p.buffer_text = True
print("opening {0}".format(sys.argv[1]))
with open(sys.argv[1]) as f:
print("file is open")
p.ParseFile(f)
print("parsing complete")
t = threading.Thread(group=None, target=do_expat)
t.start()
while True:
q_lock.acquire() <---
print(q)
q_lock.release() <---
time.sleep(1)
Вы видите, это было действительно просто, мы просто создали блокировочную переменную, чтобы защитить наш объект, и получить эту блокировку каждый раз, прежде чем мы используем объект и освободить каждый раз после того, как мы завершили нашу задачу на объекте. Таким образом мы гарантировали, что q.append (имя)
никогда не будет перекрываться с print (q)
.
(С новыми версиями Python есть также "с.... "синтаксис, который помогает не снимать блокировки или закрывать файлы или другие операции очистки, часто забываемые.)
-121--4196160-Как и многие другие, я люблю использовать временные файлы. Я использую идентификатор процесса оболочки как часть временного имени, чтобы, если одновременно выполняется несколько копий сценария, они не конфликтовали. Наконец, я тогда только перезаписать исходный файл, если сценарий успешно (с помощью логического оператора короткого замыкания - это немного плотный, но очень приятно для простых командных строк). Сложение всего этого вместе выглядит следующим образом:
some_script < file > smscrpt.$$ && mv smscrpt.$$ file
При сбое команды временный файл будет оставлен. Если вы хотите очистить от ошибки, вы можете изменить это на:
some_script < file > smscrpt.$$ && mv smscrpt.$$ file || rm smscrpt.$$
BTW, я избавился от плохого использования кошки и заменил ее на перенаправление ввода.
Использование временного файла - это IMO лучше, чем пытаясь буферными данными в трубопроводе.
Это почти побеждает цель трубопроводов для их буфера.
Я думаю, что лучший способ - использовать временный файл. Однако, если вам нужен другой подход, вы можете использовать что-то вроде awk
для буферизации входных данных в памяти до того, как ваше приложение начнет получать входные данные. Следующий скрипт буферизирует все входные данные в массиве строк
до того, как начнёт выводить их следующему потребителю.
{ lines[NR] = $0; }
END {
for (line_no=1; line_no<=NR; ++line_no) {
print lines[line_no];
}
}
Вы можете свернуть его в одну строку, если хотите:
cat file | awk '{lines[NR]=$0;} END {for(i=1;i<=NR;++i) print lines[i];}' > file
Со всем этим я бы все равно порекомендовал использовать для вывода временный файл, а затем перезаписать им исходный файл.
Использование MKTEMP (1)
или Tempfile (1)
Сохраняет вам счет необходимости придумать уникальное имя файла.