Quelle est la façon la plus simple d'ajouter une chaîne au début de chaque ligne du fichier à partir de la ligne de commande?

8

Je cherche un moyen d'ajouter de la chaîne au début de chaque ligne (même chaîne pour chaque ligne). Pas quelque chose de personnalisable mais plutôt quelque chose qui sera facile à retenir et disponible sur chaque plate-forme compatible POSIX (et chaque shell également).

syntagme
la source

Réponses:

8

Vous pouvez utiliser sed:

sed -i 's/^/your_string /' your_file

Grâce aux commentaires de Stéphane et Marco, notez que l' -ioption n'est pas POSIX. Une façon POSIX de faire ce qui précède serait

sed 's/^/your_string /' your_file > tmp_copy && mv tmp_copy your_file

ou perl:

perl -pi -e 's/^/your_string /' your_file

Explication

Les deux commandes effectuent une substitution d'expression régulière, remplaçant le début d'une ligne ( ^) par la chaîne souhaitée. Le -icommutateur dans les deux commandes s'assure que le fichier est édité sur place (c'est-à-dire que les changements sont reflétés dans le fichier au lieu d'être imprimés sur stdout).

seddevrait être disponible sur tout système d'exploitation compatible POSIX et perldevrait être disponible sur la plupart des Unices modernes, à l'exception peut-être de ceux qui ont fait l'effort de le supprimer.

Joseph R.
la source
1
Petite correction: le -icommutateur n'édite pas le fichier en place. Il crée un nouveau fichier et écrase l'original une fois terminé (preuve: l'inode change). Il n'y a pas beaucoup d'outils qui effectuent réellement l'édition sur place, ce qui est une opération dangereuse. De plus, puisque vous mentionnez POSIX, le -icommutateur n'est pas obligatoire pour un compatible POSIX sed, c'est une caractéristique de certaines implémentations particulières.
Marco
2
sed -in'est pas POSIX. C'est GNU. FreeBSD seda une option similaire, mais vous en avez besoin sed -i ''.
Stéphane Chazelas
@Marco, je sais que -icrée une copie temporaire (c'est pourquoi j'ai dit que les changements sont reflétés dans le fichier d'origine); Je voulais dire que vous obtenez la même sémantique que la substitution sur place. Veuillez vérifier que la réponse mise à jour est conforme à POSIX.
Joseph R.
À strictement parler, les modifications se reflètent dans un nouveau fichier portant le même nom que l'original.
Keith Thompson
1
J'utilise souvent $$(l'ID de processus du shell actuel) dans le cadre d'un nom de fichier temporaire; cela évite l'effort de penser à un nom unique garanti à chaque fois:command filename > filename.$$ && mv filename.$$ filename
Keith Thompson
14
:|paste -d'foo ' - - - - input > output

(je plaisante, mais vous trouverez probablement que c'est la plus rapide de toutes les solutions publiées ici: -b).

La voie canonique est:

sed 's/^/foo /' < input > output

Cependant, il n'est pas facilement adapté aux chaînes arbitraires. Par exemple,

sed "s/^/$var /"

Ne fonctionne que si $varne contient pas, &, \, /ni les caractères de nouvelle ligne.

À cet égard,

export var
awk '{print ENVIRON["var"], $0}'

ou

perl -pe '$_="$ENV{var} $_"'

fonctionnerait mieux.

Stéphane Chazelas
la source
c'est quelque chose d'intéressant ...: P
Rahul Patil
4

Je présente une solution utilisant le awkpréfixe de la chaîne "foo".

awk '{ print "foo", $0; }' input > output

awkest multiplateforme et disponible sur n'importe quel système POSIX. Il ne fait pas de modification sur place. Si vous souhaitez éditer un fichier sans en créer un second, vous devrez utiliser un fichier temporaire. Voir la sedréponse de Joseph , elle montre la syntaxe. Un autre hack consiste à utiliser la syntaxe suivante, qui consiste essentiellement à créer un fichier temporaire avec le même nom de fichier que le fichier d'origine.

{ rm file; awk '{ print "foo", $0 }' > file; } < file
Marco
la source
reducto# wc -l foo`914 foo` reducto# { rm foo ; awk '{ print "prepend" , $0 }' > foo } < foo >Cela ne semble pas fonctionner. J'essayais car la redirection vers l'original me rendait nerveux, mais ça ne démarre même pas.
kurtm
1
Cet exemple fonctionnera s'il utilise des parenthèses pour l'extérieur plutôt que des accolades.
kurtm
4

Vous pouvez éviter les problèmes de modification sur place avec les outils de flux en utilisant un outil qui effectue normalement la modification sur place - un éditeur!

ex sample.txt -c "%s/^/foo /" -c wq

Il y a un avantage supplémentaire: les commandes sont faciles et évidentes pour quiconque est familiarisé avec le seul véritable éditeur.

Mike DeAngelo
la source
2

Vous pouvez utiliser perlpour ce faire:

$ perl -pi -e 's/^/mystring /' afile.txt

Exemple

Créez un exemple de fichier.

$ seq 5 > afile.txt

$ cat afile.txt
1
2
3
4
5

Exécutez la commande ci-dessus:

$ perl -pi -e 's/^/mystring /' afile.txt

$ cat afile.txt
mystring 1
mystring 2
mystring 3
mystring 4
mystring 5
slm
la source
Perl semble être universel de nos jours, mais pendant longtemps ce n'était pas le cas. Et je parie qu'il existe quelques variantes UNIX rares qui refusent résolument d'avoir Perl dans la base. Quelque chose à savoir.
kurtm
@kurtm voir la discussion ici . Apparemment, AIX n'a ​​pas Perl par défaut et les systèmes embarqués non plus.
terdon
2
@DavidSainty - c'est assez universel. Le Q était tagué avec Bash, donc je trouve extrêmement difficile d'imaginer un système qui a Bash mais pas Perl. Quoi qu'il en soit, voici l'une des 5 réponses, plusieurs des autres montrent comment utiliser sed, j'ai montré comment utiliser Perl .... ne cherchant pas une guerre sainte en la matière.
slm
1
@DavidSainty Apparemment uniquement OpenBSD. Je suppose que j'ai fait l'hypothèse puisque les gens de l'Open ont tendance à être conservateurs quant à ce qu'ils autorisent en base. OpenBSD l'a définitivement en base.
kurtm
1
@slm: " Je trouve extrêmement difficile d'imaginer un système qui a Bash mais pas Perl ". J'ai plusieurs de ces systèmes assis sur mon bureau. (Ils se trouvent être des systèmes embarqués.)
Keith Thompson
1

Utiliser simplement Bash

 while IFS= read -r line; do echo "foo" "${line}" ; done  < input > Output

Utiliser Python

python -c "import sys; print 'foo '.join([ l for l in sys.stdin.readlines() ])" < input > Output

Si vous souhaitez éditer sur place

import fileinput
import sys

for line in fileinput.input(['inputfile'], inplace=True):
    sys.stdout.write('foo {l}'.format(l=line))

Lien de référence

Rahul Patil
la source
Pourquoi ça marche plus vite que awk?
Rahul Patil
1
Cela ne fonctionnera plus rapidement que awksur de très petits fichiers. Le comportement varie selon les implémentations d'écho, il supprime les blancs de début et de fin et traite les barres obliques inverses spécialement.
Stéphane Chazelas
@StephaneChazelas Oui. vous avez 100% raison de tester ... paste.ubuntu.com/6210934
Rahul Patil
prefix () { while IFS= read -r REPLY; do printf "%s%s\n" "$1" "$REPLY"; done; }devrait être plus correct.
Matt
1
Pourquoi {}? Je pense que @Matt suggérait que vous en fassiez une fonction nommée, à quoi bon {}sans nom de fonction?
terdon
-1

Ou vous pouvez effectuer les opérations suivantes:

vi filename.txt

Esc(pour vous assurer que vous êtes en NORMALmode), puis entrez la commande suivante:

:1,$ s/^/mystring
Dino
la source
Notez que puisque l'utilisateur pose des questions sur chaque ligne du fichier, vous pouvez le remplacer 1,$ simplement %. Cela rend la commande :%s/^/string/.
HalosGhost