Предупреждение относительно «>»
Новички Unix, которые только что узнали о перенаправлении ввода / вывода ( <
и >
), часто пробуют такие вещи, как
команда … входной_файл > the_same_file
или же
команда ... < файл > the_same_file
или, почти эквивалентно,
кошачий файл | команда ...> the_same_file
( grep
, sed
, cut
, sort
, И spell
примеры команд , которые люди склонны использовать в конструкциях , как эти.) Пользователи удивлены, обнаружив , что эти сценарии приводят к файлу становятся пустым.
Нюанс, который, кажется, не упоминается в другом ответе, можно найти в первом предложении раздела перенаправления bash (1) :
Перед выполнением команды ее ввод и вывод могут быть перенаправлены
с использованием специальных обозначений, интерпретируемых оболочкой.
Первые пять слов должны быть выделены жирным шрифтом, курсивом, подчеркнуты, увеличены, мигать, окрашены в красный цвет и отмечены значком, чтобы подчеркнуть тот факт, что оболочка выполняет запрошенное перенаправление (я)
перед выполнением команды . И помни также
Перенаправление вывода приводит к открытию файла… для записи…. Если файл не существует, он создается; если он существует, он усекается до нулевого размера.
Итак, в этом примере:
sort roster > roster
оболочка открывает roster
файл для записи, обрезая его (т. е. отбрасывая все его содержимое), до sort
запуска программы. Естественно, ничего не поделаешь для восстановления данных.
Можно наивно ожидать, что
tr "[:upper:]" "[:lower:]" < poem > poem
может быть лучше. Поскольку оболочка обрабатывает перенаправления слева направо, она открывается poem
для чтения (для tr
стандартного ввода в России), прежде чем открывает ее для записи (для стандартного вывода). Но это не помогает. Несмотря на то, что эта последовательность операций дает два дескриптора файла, они оба указывают на один и тот же файл. Когда оболочка открывает файл для чтения, содержимое все еще там, но оно все еще остается забитым до выполнения программы.
Итак, что с этим делать?
Решения включают в себя:
Проверьте, имеет ли ваша программа внутреннюю возможность указать, куда выводится результат. На это часто указывает токен -o
(или --output=
). В частности,
sort roster -o roster
примерно эквивалентно
sort roster > roster
за исключением того, что в первом случае sort
программа открывает выходной файл. И это не достаточно , чтобы открыть выходной файл умного , пока после того, как она прочитала все входной файл (ов).
Точно так же, по крайней мере, в некоторых версиях sed
есть опция -i
(edit in n place), которую можно использовать для записи вывода обратно во входной файл (опять же, после того , как все входные данные были прочитаны). Редакторы как ed
/ ex
, emacs
, pico
и vi
/ vim
разрешить пользователю редактировать текстовый файл и сохранить отредактированный текст в исходном файле. Обратите внимание, что ed
(по крайней мере) можно использовать не в интерактивном режиме.
vi
имеет связанную особенность. Если вы напечатаете , он запишет содержимое буфера редактирования в , прочитает вывод и вставит его в буфер (заменяя исходное содержимое).:%!command
Entercommand
Простой, но эффективный:
команда … входной_файл > временный_файл && mv временный_файл входной_файл
Это имеет недостаток, заключающийся в том, что, если input_file
это ссылка, она (вероятно) будет заменена отдельным файлом. Кроме того, новый файл будет принадлежать вам с защитой по умолчанию. В частности, это несет в себе риск того, что файл в конечном итоге станет доступным для чтения, даже если оригинал input_file
не был.
Варианты:
command … input_file > temp_file && cp temp_file input_file && rm temp_file
который все еще (потенциально) оставит temp_file
читабельный мир. Даже лучше:
cp input_file temp_file && command … temp_file > input_file && rm temp_file
Они сохраняют статус ссылки, владельца и режим (защиту) файла, потенциально за счет вдвое большего количества операций ввода-вывода. (Возможно, вам придется использовать опцию вроде -a
или -p
on, cp
чтобы сказать ей, чтобы сохранить атрибуты.)
command … input_file > temp_file &&
cp --attributes-only --preserve=all input_file temp_file &&
mv temp_file input_file
(разбито на отдельные строки только для удобства чтения) Это сохраняет режим файла (и, если вы root, владелец), но делает его принадлежащим вам (если вы не root) и делает его новым, отдельный файл.
Этот блог
(редактирование файлов на месте) предлагает и объясняет
{rm input_file && command …> input_file ; } < input_file
Это требует, чтобы command
была возможность обрабатывать стандартный ввод (но почти все фильтры могут). Сам блог называет это рискованным препятствием и препятствует его использованию. И это также создаст новый отдельный файл (не связанный ни с чем), принадлежащий вам и с разрешениями по умолчанию.
Пакет moreutils имеет команду под названием sponge
:
команда … input_file | губка the_same_file
Смотрите этот ответ для получения дополнительной информации.
Вот что удивило меня:
syntaxerror говорит :
[Большинство из этих решений] завершатся с ошибкой в файловой системе только для чтения, где «только для чтения» означает, что вы $HOME
будете доступны для записи, но /tmp
только для чтения (по умолчанию). Например, если у вас Ubuntu и вы загрузились в консоль восстановления, это обычно так. Кроме того , оператор здесь-документ <<<
не будет работать там , либо, так как она требует , /tmp
чтобы быть для чтения / записи ,
так как он будет писать временный файл в там.
(ср. этот вопрос включает в себя и strace
вывод)
Следующее может работать в этом случае:
Итак, в чем был вопрос?
Это была популярная тема на U & L; он адресован в следующих вопросах:
… И это не считая Super User или Ask Ubuntu. Я включил много информации из ответов на вышеупомянутые вопросы здесь в этом ответе, но не все. (То есть, для получения дополнительной информации, прочитайте перечисленные выше вопросы и ответы на них.)
PS У меня нет связи с блогом, который я цитировал выше.