Je suis tombé sur une question (sur SO lui-même) où OP doit faire l'opération d'édition et de sauvegarde dans Input_file (s) lui-même.
Je sais que pour un seul fichier d'entrée, nous pourrions faire ce qui suit:
awk '{print "test here..new line for saving.."}' Input_file > temp && mv temp Input_file
Supposons maintenant que nous devons apporter des modifications dans le même type de format de fichiers (supposons .txt ici).
Ce que j'ai essayé / pensé pour ce problème: Son approche passe par une boucle for de fichiers .txt et appeler singleawk
est un processus douloureux et NON recommandé, car cela gaspillera des cycles de processeur inutiles et pour plus de fichiers, ce serait plus lent.
Donc, que pourrait-on faire ici pour effectuer une modification inplace pour plusieurs fichiers avec un NON GNU awk
qui ne prend pas en charge l'option inplace. J'ai également parcouru ce fil Enregistrer les modifications en place avec awk mais il n'y a pas grand-chose pour NON GNU awk vice et changer plusieurs fichiers en awk
lui-même, car un awk non GNU n'aura pas d' inplace
option.
REMARQUE: Pourquoi j'ajoute unebash
balise depuis, dans ma partie réponse, j'ai utilisé des commandes bash pour renommer les fichiers temporaires en leurs noms de fichier d'entrée afin de les ajouter.
EDIT: Selon le commentaire d'Ed Sir, en ajoutant un exemple d'échantillons ici, bien que le but du code de ce fil puisse également être utilisé par l'édition générique sur place.
Exemple de fichier (s) d'entrée:
cat test1.txt
onetwo three
tets testtest
cat test2.txt
onetwo three
tets testtest
cat test3.txt
onetwo three
tets testtest
Exemple de sortie attendue:
cat test1.txt
1
2
cat test2.txt
1
2
cat test3.txt
1
2
awk
, (peut-être dans un sous-shell) ou un{...}
groupe inclus, puis écrire les résultats dans le fichier de sortie souhaité (soit pour chaque fichier d'entrée, ou un fichier combiné pour tous les fichiers d'entrée). Ensuite, vous redirigez simplement la sortie du groupe sous-shell ou accolade vers le fichier en cours d'écriture? Le simple fait d'inclure une chaîne de fichiers d'entrée à la suite de laawk
commande traiterait séquentiellement tous les fichiers (ou quelque chose de similaire) ??awk {..} file1 .. fileX
écrire le fichier modifié comme, par exempletemp01
et dans votre prochaine itération lors du traitement du fichier suivant, utilisez unmv -f tmp01 input01
pour écraser le fichier d'entrée avec les données modifiées; ou (2) il suffit d'écrire un nouveau répertoire de./tmp/tmp01 ... ./tmp/tmp0X
pendant l'exécution duawk
script et de suivre avec une boucle sur les fichiers dans le./tmp
répertoire et, par exemplemv -f "$i" "input_${i##*[^0-9]}"
(ou toute autre extension dont vous avez besoin pour remplacer les anciens fichiers d'entrée.awk
l'achèvement complet du code, la deuxième option est presque la même que celle que j'utilise dans ma suggestion. soyez reconnaissant si vous pouviez faire part de vos réflexions sur cette solution, monsieur.Réponses:
Étant donné que l'objectif principal de ce fil est de savoir comment faire pour enregistrer en place dans NON GNU
awk
, je publie d' abord son modèle qui aidera toute personne dans n'importe quel type d'exigence, ils doivent ajouter / ajouterBEGIN
etEND
sectionner dans leur code en gardant leur BLOC principal conformément à leur exigence et il devrait alors effectuer la modification sur place:REMARQUE: ce qui suit écrira toute sa sortie dans le fichier de sortie, donc si vous souhaitez imprimer quoi que ce soit sur la sortie standard, veuillez uniquement ajouter une
print...
instruction sans> (out)
suivre.Modèle générique:
Solution d'échantillon fournie spécifique:
J'ai trouvé l'approche suivante en
awk
elle-même (pour les échantillons ajoutés, voici mon approche pour résoudre ce problème et enregistrer la sortie dans Input_file lui-même)REMARQUE: ceci n'est qu'un test pour enregistrer la sortie éditée dans Input_file (s) lui-même, on pourrait utiliser sa section BEGIN, ainsi que sa section END dans leur programme, la section principale devrait être conforme aux exigences de la question spécifique elle-même.
Juste avertissement: Étant donné que cette approche crée un nouveau fichier de sortie temporaire dans le chemin, assurez-vous qu'il y a suffisamment d'espace sur les systèmes, mais au final, cela ne gardera que les fichiers d'entrée principaux, mais pendant les opérations, il a besoin d'espace sur le système / répertoire
Voici un test pour le code ci-dessus.
Exécution du programme avec un exemple: Supposons que les
.txt
fichiers d'entréesont lessuivants:Maintenant, lorsque nous exécutons le code suivant:
REMARQUE: j'ai une place
ls -lhtr
danssystem
section intentionnellement pour voir quels fichiers de sortie il crée (base temporaire) car plus tard, il les renommera en leur nom réel.Lorsque nous exécutons un script
ls -lhtr
après l'awk
exécution, nous ne pouvons y voir que des.txt
fichiers.Explication: Ajout d'une explication détaillée de la commande ci-dessus ici:
la source
FNR==1
bloc, vous pouvez toujours enregistrer les modifications sur place. Commeawk 'FNR==1{system("rm " FILENAME)} {print "new lines" > FILENAME}' files...
. Ce n'est pas fiable du tout (une perte de données complète est susceptible de se produire), mais cela fonctionne généralement bien: DJ'irais probablement avec quelque chose comme ça si j'essayais de faire ça:
J'aurais préféré copier le fichier d'origine dans la sauvegarde d'abord, puis opérer sur les modifications de sauvegarde de l'original, mais cela changerait la valeur de la variable FILENAME pour chaque fichier d'entrée, ce qui n'est pas souhaitable.
Notez que si vous aviez un fichier original nommé
whatever.bak
ouwhatever.new
dans votre répertoire, vous devez le remplacer par des fichiers temporaires, vous devez donc également ajouter un test pour cela. Un appel àmktemp
pour obtenir les noms des fichiers temporaires serait plus robuste.La chose la plus utile à avoir dans cette situation serait un outil qui exécute toute autre commande et effectue la partie d'édition "sur place" car cela pourrait être utilisé pour fournir une édition "sur place" pour POSIX sed, awk, grep, tr, peu importe et ne vous obligerait pas à changer la syntaxe de votre script en
print > out
etc. à chaque fois que vous souhaitez imprimer une valeur. Un exemple simple et fragile:que vous utiliseriez comme suit:
Un problème évident avec cela
inedit
script est la difficulté d'identifier les fichiers d'entrée / sortie séparément de la commande lorsque vous avez plusieurs fichiers d'entrée. Le script ci-dessus suppose que tous les fichiers d'entrée apparaissent sous forme de liste à la fin de la commande et la commande est exécutée contre eux un par un, mais bien sûr cela signifie que vous ne pouvez pas l'utiliser pour des scripts qui nécessitent 2 fichiers ou plus à une heure, par exemple:ou des scripts qui définissent des variables entre les fichiers de la liste arg, par exemple:
Le rendre plus robuste à gauche comme exercice pour le lecteur, mais regardez le
xargs
synopsis comme point de départ pour savoir comment un robusteinedit
devrait fonctionner :-).la source
La solution shell est simple et probablement assez rapide:
Ne recherchez une solution différente que si vous avez démontré de manière concluante qu'elle est trop lente. Rappelez-vous: l'optimisation prématurée est la racine de tout mal.
la source