Est-il possible d'utiliser l'option -i inplace
et d'imprimer aussi des choses à stdout
?
Par exemple, si je voulais mettre à jour un file, et s'il y a des modifications, imprimer le nom du file et les lignes modifiées en stderr
je pourrais faire quelque chose comme
find -type f -name 'myfiles' -exec gawk -i inplace '{if(gsub(/pat/, "repl")) { print FILENAME > "/proc/self/fd/2" ; print > "/proc/self/fd/2"; } print;}' {} +
mais existe-t-il un moyen d'utiliser stdout
place, ou un moyen plus propre d'imprimer ce bloc au stream alternatif?
Vous devriez utiliser /dev/stderr
ou /dev/fd/2
au lieu de /proc/self/fd/2
. gawk
gère /dev/fd/x
et /dev/stderr
par lui-même (que le système ait ces files ou non).
Quand vous faites un:
print "x" > "/dev/fd/2"
gawk
fait une write(2, "x\n")
, alors que quand vous le faites:
print "x" > "/proc/self/fd/2"
puisqu'il ne traite pas spécialement /proc/self/fd/x
, il fait un:
fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC); write(fd, "x\n");
Premier /proc/self/fd
est spécifique à Linux et sur Linux ils sont problématiques. Les deux versions ci-dessus ne sont pas équivalentes lorsque stderr est à un file normal ou autre, ou à un socket (pour lequel ce dernier échouerait) (sans oublier qu'il gaspille un descripteur de file).
Cela étant dit, si vous avez besoin d'écrire dans la sortie standard, vous devez la sauvegarder dans un autre file tel que:
gawk -i inplace '{ print "goes into the-file" print "to stdout" > "/dev/fd/3"}' the-file 3>&1
gawk
redirige stdout avec in-place vers le file. C'est nécessaire parce que, par exemple, vous voudriez:
awk -i inplace '{system("uname")}' file
pour stocker la sortie uname
dans le file
.
Juste pour le plaisir, une approche alternative utilisant uniquement les fonctionnalités POSIX de find
, sh
, grep
et (notamment) ex
:
find . -type f -name 'myfiles' -exec sh -c ' for f do grep -q "pat" "$f" && { printf "%s\n" "$f"; printf "%s\n" "%s/pat/repl/g" x | ex "$f"; }; done' find-sh {} +
(Tous les sauts de ligne de la command ci-dessus sont facultatifs, ils peuvent être condensés en une seule ligne.)
Ou, sans doute plus lisiblement:
find . -type f -name 'myfiles' -exec sh -c ' for f do if grep -q "pat" "$f"; then printf "%s\n" "$f" printf "%s\n" "%s/pat/repl/g" x | ex "$f" fi done' find-sh {} +
🙂
(Cette command n'est pas testée, les modifications sont les bienvenues si je fais des modifications.)