O operador de redirecionamento para abrir um arquivo no modo de leitura + gravação sem truncamento é <>
em todos os shells semelhantes a Bourne (que mapeia para open(file, O_RDWR|O_CREAT)
(embora zsh
também ative O_NOCTTY
) ou fopen(file, "w+")
):
exec 3<> "$file"
abre o $file
no descritor de arquivo 3 no modo leitura + gravação (sem truncá-lo e criá-lo se ele não existir).
No entanto, apenas ksh93
e zsh
têm procurando operadores. dd
pode procurar, mas não para trás. E note que nenhum shell, exceto zsh
, pode ter bytes NUL em suas variáveis.
Em 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
Em 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
Portualmente, você ainda pode abrir o arquivo várias vezes, para cada deslocamento desejado, como aqui para ler e escrever 2 bytes no deslocamento 2 (desde que não sejam bytes com valor 0 se não estiver usando zsh
):
var=$(dd bs=2 count=1 skip=1 < "$file"; echo .)
var=${var%?}
printf %s something-else | dd bs=2 seek=1 1<> "$file"
Ou:
printf %s something-else | dd bs=2 seek=1 of="$file" conv=notrunc
Para ler e gravar no mesmo arquivo, ksh93
tem dois outros operadores de redirecionamento interessantes:
tr 01 10 < file >; file
Armazenaria a saída de tr
em um arquivo temporário e se tr
for bem-sucedida, renomeie para file
(cuidado com o fato de o arquivo ser criado novamente, portanto com permissões e propriedade possivelmente diferentes).
tr -d 0 < file 1<>; file
O mesmo que o padrão / Bourne tr -d 0 < file 1<> file
, exceto que, se tr
tiver êxito, file
será truncado onde tr
terminou de gravar. Você pode usar isso para comandos de filtro que produzem menos saída do que a entrada de leitura ou, mais precisamente, comandos que não lêem dados que eles escreveram anteriormente.
E zsh
tem a forma =(...)
de substituição de processo que você pode usar como:
mv =(tr 01 10 < file) file
(com efeito e advertências similares a ksh93
's >;
). Ou:
cp =(tr 01 10 < file) file
que preservaria os atributos de file
, mas significa uma cópia extra.
Agora, se você precisar ler e escrever no mesmo deslocamento usando o mesmo descritor de arquivo e nem o zsh nem o ksh93 estiverem disponíveis, você sempre poderá reverter para perl
/ python
/ ruby
...
perl -e '
open F, "<>", "file" or die "open: $!";
read F, $var, 1;
seek F, 0, 0;
print F "something-else"'
Agora, depois de reler a versão atualizada da sua pergunta, parece que seu arquivo está se comportando mais como um soquete ou canal bidirecional e não como um arquivo normal e pesquisável.
Nesse caso, pode ser apenas uma questão de:
socat - file:your-file
ou:
(cat >&3 3>&- & cat <&3 3<&-) 3<> your-file
para alimentar dados de e para esse arquivo como lidos de / para stdin / stdout.
Note que cada cat
lê / escreve em sua própria cópia do descritor de arquivo 3 aberto pelo shell, mas eles compartilham a mesma descrição do arquivo aberto , portanto deve ser equivalente.