Чтение и запись в файл из stdin и stdout

Один из способов с использованием функции split:

awk 'FNR==NR{a[$1]=$6; next}
{split($0, b, ","); u=b[1]; if (u in a) {$0=$0","a[u]}}
1' file2 file1

Она сохраняет 6-е поле из file2 в a[1st field], затем для каждой строки file1 разбивает ее через запятую на массив b и присваивает первый элемент b[1] в u. Если u находится в a, он добавляет запятую и a[u] к строке. Заключительный 1 печатает каждую строку file1 независимо от того, была она изменена или нет.

2
21.03.2016, 13:31
2 ответа

Если вы не делаете перевод только, вы не можете безопасно читать и писать одновременно (и даже при переводе возможно, что файл окажется "наполовину переведенным", если программа завершится с ошибкой).

Похоже, вам действительно нужна какая-то комбинация tee и sponge. Вы можете использовать sponge из moreutils для поглощения стандартного ввода и последующей записи его в файл. Вы можете использовать tee для дублирования ввода на несколько выходов.

Конечный результат будет выглядеть примерно так:

command < filename | tee >(sponge filename)

>() - это пример подстановки процесса. В этом случае >(имя файла губки) заменяется на путь к FIFO, который идет на stdin губки, куда пишет tee. tee также записывает свой вход в stdout независимо.

Вот пример. Видно, что вывод записывается и в stdout, и в файл.

$ echo 'foo bar' > file
$ sed 's/foo/qux/' < file | tee >(sponge file)
qux bar
$ cat file
qux bar
0
29.04.2021, 00:16

Оператор перенаправления для открытия файла в режиме чтения + записи без усечения - <> во всех оболочках типа Борна (который соответствует open (file, O_RDWR | O_CREAT) (хотя zsh также выдает O_NOCTTY ) или fopen (file, "w +") ):

exec 3<> "$file"

открывает $ файл в файловом дескрипторе 3 в режиме чтения + записи (без его усечения и создания, если он не существует).

Однако только ksh93 и zsh имеют ищущие операторы. dd может искать, но не назад. И обратите внимание, что никакая оболочка, кроме zsh , не может иметь байтов NUL в своих переменных.

В zsh :

zmodload zsh/system
exec 3<> $file
sysread -i 3 -c 2 var # a read() of 2 bytes
sysseek -u 3 0 # seek back to beginning
# or sysseek -u 3 -w current -2 # to seek back 2 bytes
syswrite -o 3 something-else
exec 3<&- # close

В ksh93 :

exec 3<> "$file"
var=$(dd bs=2 count=1 <&3 2>/dev/null; echo .)
var=${var%?}
exec 3<#((0)) # seek to beginning
# or exec 3<#((CUR-2)) # to seek back 2 bytes
print -ru3 something-else

В переносном режиме вы все равно можете открывать файл несколько раз для каждого желаемого смещения, например, здесь для чтения и записи 2 байта со смещением 2 (при условии, что это не байты со значением 0, если не используется zsh ):

var=$(dd bs=2 count=1 skip=1 < "$file"; echo .)
var=${var%?}
printf %s something-else | dd bs=2 seek=1 1<> "$file"

Или:

printf %s something-else | dd bs=2 seek=1 of="$file" conv=notrunc

Для чтения и записи в один и тот же файл, ksh93 имеет два других интересных оператора перенаправления:

tr 01 10 < file >; file

сохранит вывод tr во временном файле, и если tr успешно, переименуйте его в файл ( будьте осторожны, файл создается заново, поэтому, возможно, с другими разрешениями и владельцами).

tr -d 0 < file 1<>; file

То же, что и стандартный / Bourne tr -d 0 file , за исключением того, что в случае успеха tr файл усекается, где tr закончил писать. Вы можете использовать это для команд фильтрации, которые производят меньше результатов, чем они читают ввод, или, точнее, команд, которые не будут читать данные, которые они ранее записали.

А zsh имеет форму замены процесса = (...) , которую можно использовать как:

 mv =(tr 01 10 < file) file

(с таким же эффектом и оговорками, как ksh93 : >; ). Или:

 cp =(tr 01 10 < file) file

, который сохранит атрибуты файла , но означает дополнительную копию.


Теперь, если вам нужно читать и писать с одного и того же смещения с использованием одного и того же файлового дескриптора, и ни zsh, ни ksh93 недоступны, вы всегда можете вернуться к perl / python / рубин ...

perl -e '
  open F, "<>", "file" or die "open: $!";
  read F, $var, 1;
  seek F, 0, 0;
  print F "something-else"'

Теперь, после перечитывания обновленной версии вашего вопроса, похоже, что ваш файл ведет себя больше как сокет или двунаправленный канал, а не как обычный файл с возможностью поиска.

В этом случае, это может быть просто вопрос:

socat - file:your-file

или:

(cat >&3 3>&- & cat <&3 3<&-) 3<> your-file

, чтобы передать данные из этого файла и в этот файл как прочитанные из / в стандартный ввод / вывод.

Обратите внимание, что каждый cat читает / записывает в свою собственную копию файлового дескриптора 3, открытого оболочкой, но они используют одно и то же описание открытого файла , поэтому оно должно быть эквивалентным.

4
29.04.2021, 00:16

Теги

Похожие вопросы