C'est probablement une solution complexe .
Je recherche un opérateur simple comme ">>", mais en préfixe.
J'ai peur que cela n'existe pas. Je vais devoir faire quelque chose comme
mv myfile tmp cat myheader tmp> myfile
Quelque chose de plus intelligent?
mktemp
? Vous pouvez toujours nettoyer le fichier temporaire par la suite ...Réponses:
Le hack ci-dessous était une réponse rapide et spontanée qui a fonctionné et a reçu beaucoup de votes positifs. Puis, au fur et à mesure que la question devenait plus populaire et que le temps passait, des gens indignés ont commencé à signaler que cela fonctionnait en quelque sorte mais que des choses étranges pouvaient arriver, ou que cela ne fonctionnait tout simplement pas, alors il a été furieusement déclassé pendant un certain temps. Si amusant.
La solution exploite l'implémentation exacte des descripteurs de fichiers sur votre système et, comme l'implémentation varie considérablement entre les nœuds, son succès dépend entièrement du système, définitivement non portable et ne doit pas être invoqué pour quelque chose, même vaguement important.
Maintenant, avec tout cela à l'écart, la réponse était:
Créer un autre descripteur de fichier pour le fichier (
exec 3<> yourfile
) puis écrire dans ce (>&3
) semble surmonter le dilemme de lecture / écriture sur le même fichier. Fonctionne pour moi sur des fichiers 600K avec awk. Cependant, essayer la même astuce en utilisant «chat» échoue.Passer le préfixe comme variable à awk (
-v TEXT="$text"
) résout le problème des guillemets littéraux qui empêche de faire cette astuce avec 'sed'.la source
Cela utilise toujours un fichier temporaire, mais au moins il est sur une ligne:
Crédit: BASH: ajouter un texte / des lignes à un fichier
la source
-
aprèscat
?echo -n "text"
yourfile
s'agit d'un lien symbolique, cela ne fera pas ce que vous voulez.ed est l'éditeur standard! http://www.gnu.org/fun/jokes/ed.msg.html
la source
0r header.file
echo -e '0a\nyour text here\n.\nw' | ed some_file
John Mee: votre méthode n'est pas garantie de fonctionner, et échouera probablement si vous ajoutez plus de 4096 octets de trucs (du moins c'est ce qui se passe avec gnu awk, mais je suppose que d'autres implémentations auront des contraintes similaires). Non seulement il échouera dans ce cas, mais il entrera dans une boucle sans fin où il lira sa propre sortie, faisant ainsi grossir le fichier jusqu'à ce que tout l'espace disponible soit rempli.
Essayez-le par vous-même:
(avertissement: tuez-le après un certain temps ou il remplira le système de fichiers)
De plus, il est très dangereux d'éditer des fichiers de cette façon, et c'est un très mauvais conseil, comme si quelque chose se passait pendant que le fichier était en cours d'édition (plantage, disque plein), vous êtes presque assuré de rester avec le fichier dans un état incohérent.
la source
Pas possible sans fichier temporaire, mais voici un oneliner
Vous pouvez utiliser d'autres outils tels que ed ou perl pour le faire sans fichiers temporaires.
la source
Il peut être intéressant de noter que c'est souvent une bonne idée de générer en toute sécurité le fichier temporaire à l'aide d'un utilitaire comme mktemp , du moins si le script sera un jour exécuté avec les privilèges root. Vous pouvez par exemple faire ce qui suit (encore une fois dans bash):
la source
Si vous en avez besoin sur les ordinateurs que vous contrôlez, installez le paquet "moreutils" et utilisez "sponge". Ensuite, vous pouvez faire:
la source
{ echo "prepended text"; cat myfile } | sponge myfile
En utilisant un heredoc bash, vous pouvez éviter le besoin d'un fichier tmp:
Cela fonctionne car $ (cat myfile) est évalué lorsque le script bash est évalué, avant que le chat avec redirection ne soit exécuté.
la source
en supposant que le fichier que vous souhaitez modifier est my.txt
Et le fichier que vous souhaitez ajouter est en-tête
Assurez-vous d'avoir une dernière ligne vierge dans le fichier d'en-tête.
Maintenant, vous pouvez l'ajouter avec
Vous vous retrouvez avec
Autant que je sache, cela ne fonctionne que dans «bash».
la source
this is the header
dans my.txt. Même après avoir mis à jour Bash pour4.3.42(1)-release
obtenir le même résultat.<(...)
) écrit, il n'y a donc aucune garantie qu'ilmy.txt
soit lu en entier à l'avance , sans lequel cette technique ne fonctionnera pas.Lorsque vous commencez à essayer de faire des choses qui deviennent difficiles dans un script shell, je suggère fortement de chercher à réécrire le script dans un langage de script "approprié" (Python / Perl / Ruby / etc)
En ce qui concerne l'ajout d'une ligne à un fichier, il n'est pas possible de le faire via un tuyau, car lorsque vous faites quelque chose de similaire
cat blah.txt | grep something > blah.txt
, cela vide le fichier par inadvertance. Il existe une petite commande utilitaire appelée quesponge
vous pouvez installer (vous le faitescat blah.txt | grep something | sponge blah.txt
et elle met en mémoire tampon le contenu du fichier, puis l'écrit dans le fichier). Il est similaire à un fichier temporaire mais vous n'avez pas à le faire explicitement. mais je dirais que c'est une condition "pire" que, disons, Perl.Il peut y avoir un moyen de le faire via awk, ou similaire, mais si vous devez utiliser un script shell, je pense qu'un fichier temporaire est de loin le moyen le plus simple (/ seulement?) ..
la source
Comme le suggère Daniel Velkov, utilisez un tee.
Pour moi, c'est une solution simple et intelligente:
la source
EDIT: C'est cassé. Voir un comportement étrange lors de l'ajout d'un fichier avec chat et tee
La solution de contournement au problème d'écrasement consiste à utiliser
tee
:la source
Celui que j'utilise. Celui-ci vous permet de spécifier l'ordre, les caractères supplémentaires, etc. comme vous le souhaitez:
PS: seulement cela ne fonctionne pas si les fichiers contiennent du texte avec une barre oblique inverse, car il est interprété comme des caractères d'échappement
la source
Surtout pour le plaisir / golf, mais
fera l'affaire, et il n'y a pas de pipelines ou de redirections. Bien sûr, vi / ex n'est pas vraiment destiné à une utilisation non interactive, donc vi clignotera brièvement.
la source
Pourquoi ne pas simplement utiliser la commande ed (comme déjà suggéré par fluffle ici)?
ed lit le fichier entier en mémoire et effectue automatiquement une édition de fichier sur place!
Donc, si votre fichier n'est pas si énorme ...
Une autre solution de contournement consisterait à utiliser des descripteurs de fichiers ouverts comme suggéré par Jürgen Hötzel dans Rediriger la sortie de sed 's / c / d /' myFile vers myFile
Tout cela pourrait être mis sur une seule ligne, bien sûr.
la source
Une variante de la solution de cb0 pour "pas de fichier temporaire" pour ajouter du texte fixe:
Encore une fois, cela repose sur l'exécution du sous-shell - le (..) - pour éviter que le chat refuse d'avoir le même fichier pour l'entrée et la sortie.
Remarque: j'ai aimé cette solution. Cependant, sur mon Mac, le fichier d'origine est perdu (je pense qu'il ne devrait pas, mais c'est le cas). Cela pourrait être résolu en écrivant votre solution sous la forme: echo "text to prepend" | cat - file_to_be_modified | cat> tmp_file; mv tmp_file file_to_be_modified
la source
Voici ce que j'ai découvert:
la source
la source
ATTENTION: cela nécessite un peu plus de travail pour répondre aux besoins du PO.
Il devrait y avoir un moyen de faire fonctionner l'approche sed de @shixilun malgré ses réticences. Il doit y avoir une commande bash pour échapper les espaces lors de la lecture d' un fichier dans une chaîne de substitution sed (par exemple remplacer des caractères de nouvelle ligne avec « \ n ». Les commandes shell
vis
etcat
peut traiter avec des caractères non imprimables, mais pas blancs, donc cela ne résoudra pas les années OP problème:échoue en raison des nouvelles lignes brutes dans le script de remplacement, qui doivent être précédées d'un caractère de continuation de ligne () et peut-être suivi d'un &, pour que le shell et sed soient heureux, comme cette réponse SO
sed
a une taille limite de 40K pour les commandes de recherche-remplacement non globales (pas de / g de fin après le modèle), ce qui éviterait probablement les problèmes effrayants de dépassement de tampon de awk dont anonyme a averti.la source
la source
Avec $ (command), vous pouvez écrire la sortie d'une commande dans une variable. Je l'ai donc fait en trois commandes sur une seule ligne et sans fichier temporaire.
la source
Si vous avez un gros fichier (quelques centaines de kilo-octets dans mon cas) et un accès à python, c'est beaucoup plus rapide que les
cat
solutions de pipe:python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'
la source
Une solution avec
printf
:Vous pouvez également faire:
Mais dans ce cas, vous devez vous assurer qu'il n'y en a pas n'importe
%
où, y compris le contenu du fichier cible, car cela peut être interprété et bousiller vos résultats.la source
echo
semble être une option plus sûre.echo "my new line\n$(cat my/file.txt)" > my/file.txt
${new_line}
, pas du fichier cibleVous pouvez utiliser la ligne de commande perl:
Où -i créera un remplacement en ligne du fichier et -0777 slurp le fichier entier et fera correspondre ^ uniquement le début. -pe imprimera toutes les lignes
Ou si my_header est un fichier:
Où le / e permettra une évaluation du code dans la substitution.
la source
où "mon_fichier" est le fichier auquel ajouter "ma_ chaîne".
la source
J'aime l' approche ed de @ fluffle le mieux l' . Après tout, les commutateurs de ligne de commande de n'importe quel outil par rapport aux commandes de l'éditeur scripté sont essentiellement la même chose ici; ne pas voir une solution d'éditeur scripté "propreté" étant moindre ou quoi que ce soit.
Voici mon one-liner ajouté pour
.git/hooks/prepare-commit-msg
ajouter un.gitmessage
fichier dans le dépôt pour valider les messages:Exemple
.gitmessage
:Je fais à la
1r
place de0r
, car cela laissera la ligne vide prête à écrire au-dessus du fichier du modèle d'origine. Ne mettez pas une ligne vide au-dessus de votre.gitmessage
alors, vous vous retrouverez avec deux lignes vides.-s
supprime la sortie des informations de diagnostic de ed.En relation avec cela, j'ai découvert que pour les amateurs de vim, il est également bon d'avoir:
la source
variables, ftw?
la source
Je pense que c'est la variante la plus propre d'ed:
en tant que fonction:
la source
Si vous créez un script dans BASH, en fait, vous pouvez simplement émettre:
C'est en fait dans l'exemple complexe que vous avez vous-même publié dans votre propre question.
la source
cat - yourfile <<<"text" > /tmp/out && mv /tmp/out yourfile
, mais c'est suffisamment différent de ma réponse pour que ce soit sa propre réponse.À mon humble avis, il n'y a pas de solution shell (et n'en sera jamais une) qui fonctionnerait de manière cohérente et fiable quelle que soit la taille des deux fichiers
myheader
etmyfile
. La raison en est que si vous voulez faire cela sans revenir à un fichier temporaire (et sans laisser le shell se répéter silencieusement dans un fichier temporaire, par exemple via des constructions commeexec 3<>myfile
, piping totee
, etc.La "vraie" solution que vous recherchez doit manipuler le système de fichiers, elle n'est donc pas disponible dans l'espace utilisateur et dépendra de la plate-forme: vous demandez de modifier le pointeur du système de fichiers utilisé par
myfile
la valeur actuelle du pointeur du système de fichiers pourmyheader
et remplacer dans le système de fichierEOF
demyheader
avec un lien enchaînée à l'adresse du système de fichiers en cours pointé parmyfile
. Ce n'est pas anodin et ne peut évidemment pas être fait par un non-super-utilisateur, et probablement pas par le super-utilisateur non plus ... Jouez avec les inodes, etc.Cependant, vous pouvez plus ou moins simuler cela en utilisant des périphériques en boucle. Voir par exemple ce fil SO .
la source