On pourrait résoudre le problème de la manière suivante:
cat file | some_sed_command | tee file >/dev/null
Non .
Les chances file
seront tronquées, mais aucune garantie cat file | some_sed_command | tee file >/dev/null
ne sera tronquée file
.
Tout dépend de la commande qui est traitée en premier, contrairement à ce que l'on peut attendre, les commandes d'un canal ne sont pas traitées de gauche à droite . Il n'y a aucune garantie quant à la commande qui sera choisie en premier, donc on pourrait tout aussi bien la considérer comme choisie au hasard et ne jamais compter sur le shell qui ne choisit pas la faute.
Étant donné que les chances que la commande incriminée soit choisie en premier entre trois commandes sont plus faibles que les chances que la commande incriminée soit choisie en premier entre deux commandes, il est moins probable qu'elle file
soit tronquée, mais cela se produira toujours .
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
Alors n'utilisez jamais quelque chose comme ça cat file | some_sed_command | tee file >/dev/null
. Utilisez sponge
comme Oli l'a suggéré.
Comme alternative, pour des environnements plus légers et / ou des fichiers relativement petits, on peut utiliser une chaîne ici et une substitution de commande pour lire le fichier avant d'exécuter une commande:
$ cat file
foo
bar
$ for ((i=0; i<100; i++)); do <<<"$(<file)" sed 's/bar/baz/' >file; done
$ cat file
foo
baz