Si potrebbe risolvere il problema nel modo seguente:
cat file | some_sed_command | tee file >/dev/null
No .
Le probabilità file
verranno troncate, ma non ci sono garanzie cat file | some_sed_command | tee file >/dev/null
che non troncano file
.
Tutto dipende da quale comando viene elaborato per primo, al contrario di quello che ci si può aspettare, i comandi in una pipe non vengono elaborati da sinistra a destra . Non vi è alcuna garanzia su quale comando verrà scelto per primo, quindi si potrebbe anche solo pensarlo come scelto casualmente e non fare affidamento sulla shell che non sceglie quello offensivo.
Poiché le possibilità che il comando incriminato venga selezionato per primo tra tre comandi sono inferiori alle possibilità che il comando incriminato venga selezionato per primo tra due comandi, è meno probabile che file
venga troncato, ma continuerà a succedere .
script.sh
:
#!/bin/bash
for ((i=0; i<100; i++)); do
cat >file <<-EOF
foo
bar
EOF
cat file |
sed 's/bar/baz/' |
tee file >/dev/null
[ -s file ] &&
echo 'Not truncated' ||
echo 'Truncated'
done |
sort |
uniq -c
rm file
% bash script.sh
93 Not truncated
7 Truncated
% bash script.sh
98 Not truncated
2 Truncated
% bash script.sh
100 Not truncated
Quindi non usare mai qualcosa del genere cat file | some_sed_command | tee file >/dev/null
. Usa sponge
come suggerito da Oli.
In alternativa, per ambienti più forti e / o file relativamente piccoli, è possibile utilizzare una stringa qui e una sostituzione comando per leggere il file prima di eseguire qualsiasi comando:
$ cat file
foo
bar
$ for ((i=0; i<100; i++)); do <<<"$(<file)" sed 's/bar/baz/' >file; done
$ cat file
foo
baz