Comment changer un fichier sur place en utilisant awk? (comme avec «sed -i»)

11

J'ai un awkscript new.awk:

 BEGIN { FS=OFS="," }
 NR==1 {
for (i=1; i<=NF; i++) {
    f[$i] = i
}
   } 
  NR > 1 {
 begSecs= mktime(gensub(/[":-]/," ","g",$(f["DateTime"])))
 endSecs = begSecs + $(f["TotalDuration"])
 $(f["CallEndTime"]) = strftime("%Y-%m-%d %H:%M:%S", endSecs)
 }
 { print }

J'appelle ça en coquille

awk new.awk sample.csv

... mais je peux voir les changements dans le terminal. Comment effectuer la modification sur place dans le fichier, comme lors de l'utilisation sed -i?

mittu
la source

Réponses:

16

GNU awk(communément trouvé sur les systèmes Linux), depuis la version 4.1.0, est capable d'inclure une " awkbibliothèque source" avec -iou --includesur la ligne de commande. L'une des bibliothèques sources distribuées avec GNU awkest celle appelée inplace:

$ cat file
hello
there
$ awk -i inplace '/hello/ { print "oh,", $0 }' file
$ cat file
oh, hello

Comme vous pouvez le voir, cela fait que la sortie du awkcode remplace le fichier d'entrée. La ligne disant theren'est pas conservée car elle n'est pas sortie par le programme.

Avec un awkscript dans un fichier, vous l'utiliseriez comme

awk -i inplace -f script.awk datafile

Si la awkvariable INPLACE_SUFFIXest définie sur une chaîne, la bibliothèque effectuera une sauvegarde du fichier d'origine avec cela comme suffixe de nom de fichier.

awk -i inplace -v INPLACE_SUFFIX=.bak -f script.awk datafile

Si vous avez plusieurs fichiers d'entrée, chaque fichier doit être modifié individuellement sur place. Mais vous pouvez désactiver l'édition sur place pour un fichier (ou un ensemble de fichiers) en utilisant inplace=0sur la ligne de commande avant ce fichier:

awk -i inplace -f script.awk file1 file2 inplace=0 file3 inplace=1 file4

Dans la commande ci-dessus, file3ne serait pas modifié sur place.


Pour une "édition sur place" plus portable d'un seul fichier, utilisez

tmpfile=$(mktemp)
cp file "$tmpfile" &&
awk '...some program here...' "$tmpfile" >file
rm "$tmpfile"

Cela copierait le fichier d'entrée dans un emplacement temporaire, puis appliquerait le awkcode sur le fichier temporaire lors de la redirection vers le nom de fichier d'origine.

Les opérations dans cet ordre (exécutées awksur le fichier temporaire et non sur le fichier d'origine) garantissent que les métadonnées du fichier (autorisations et propriété) du fichier d'origine ne sont pas modifiées.

Kusalananda
la source
4

Essaye ça.

awk  new.awk sample.csv > tmp.csv && mv -f tmp.csv sample.csv
  • rediriger la sortie vers un fichier temporaire.
  • puis déplacez le contenu du fichier temporaire vers le fichier d'origine.
Siva
la source
1
Si vous regardez le code source awk inplace, c'est exactement ce qu'il fait: crée un fichier temporaire, redirige stdout là et à la fin le renomme dans le fichier d'entrée.
chx