Question

C'est probablement une solution complexe.

Je suis à la recherche d'un opérateur simple, comme ">>", mais de préparer.

Je crains qu'il n'existe pas.Je vais devoir faire quelque chose comme

 mv myfile tmp
 cat myheader tmp > myfile

Rien de plus intelligent?

Était-ce utile?

La solution

L' hack ci-dessous a été un rapide hors-la-brassard réponse qui a travaillé et a reçu beaucoup de upvotes.Alors, la question est devenue plus populaire et plus le temps passait, outragé les gens ont commencé des rapports qu'il sorta de travail mais des choses étranges qui pourrait arriver, ou ça ne fonctionne pas du tout, donc c'était furieusement downvoted pour un temps.Amusant.

La solution exploite l'exacte mise en œuvre de descripteurs de fichiers sur votre système et que, en raison de la mise en œuvre varie considérablement entre les nixes, c'est le succès est entièrement dépendante du système, définitivement non portable, et ne doit pas être invoqué pour n'importe quoi, même vaguement important.

Maintenant, avec tout ça de la manière la réponse a été:


La création d'un autre descripteur de fichier pour le fichier (exec 3<> yourfile) de là, vers l'écriture (>&3) semble dépasser la lecture/écriture sur le même fichier dilemme.Fonctionne pour moi sur 600K fichiers avec awk.Cependant essayé le même truc à l'aide de 'chat' échoue.

En passant la prependage comme une variable awk (-v TEXT="$text") de surmonter les citations littérales problème qui l'empêche de faire ce truc avec sed.

#!/bin/bash
text="Hello world
What's up?"

exec 3<> yourfile && awk -v TEXT="$text" 'BEGIN {print TEXT}{print}' yourfile >&3

Autres conseils

Ce toujours utilise un fichier temporaire, mais au moins il est sur une seule ligne:

echo "text" | cat - yourfile > /tmp/out && mv /tmp/out yourfile

Crédit: BASH:Ajouter Un Texte ou des Lignes D'un Fichier

echo '0a
your text here
.
w' | ed some_file

ed est le Standard de l'Éditeur! http://www.gnu.org/fun/jokes/ed.msg.html

Jean-Mee:votre méthode n'est pas garanti, et va probablement échouer si vous la faire précéder de plus de 4 096 octets de choses (du moins, c'est ce qui se passe avec gnu awk, mais je suppose que d'autres implémentations ont les mêmes contraintes).Non seulement il va échouer dans ce cas, mais il va entrer dans une boucle sans fin où il va lire sa propre production, ce qui rend le fichier de croître jusqu'à ce que tout l'espace disponible est rempli.

Essayez par vous-même:

exec 3<>myfile && awk 'BEGIN{for(i=1;i<=1100;i++)print i}{print}' myfile >&3

(avertissement:le tuer après un certain temps ou il va remplir le système de fichiers)

En outre, il est très dangereux de modifier les fichiers de cette façon, et c'est très mauvais conseils, comme si quelque chose se passe alors que le fichier est en cours de modification (crash disque plein), vous êtes presque assuré d'être de gauche avec le fichier dans un état incohérent.

Pas possible sans un fichier temp, mais voici un oneliner

{ echo foo; cat oldfile; } > newfile && mv newfile oldfile

Vous pouvez utiliser d'autres outils tels que l'ed ou perl pour le faire sans les fichiers temporaires.

Il peut être intéressant de noter que c'est souvent un bonne idée pour générer en toute sécurité le fichier temporaire à l'aide d'un utilitaire comme mktemp, au moins si le script ne sera jamais exécuté avec les privilèges de root.Par exemple, vous pouvez effectuer les opérations suivantes (à nouveau en bash):

(tmpfile=`mktemp` && { echo "prepended text" | cat - yourfile > $tmpfile && mv $tmpfile yourfile; } )

Si vous avez besoin de ce sur des ordinateurs de contrôle, installez le paquet "moreutils" et l'utilisation "d'éponge".Ensuite, vous pouvez faire:

cat header myfile | sponge myfile

À l'aide d'un bash heredoc vous pouvez éviter la nécessité d'un fichier tmp:

cat <<-EOF > myfile
  $(echo this is prepended)
  $(cat myfile)
EOF

Cela fonctionne parce que $(cat monfichier) est évaluée lorsque le script bash qui est évalué, avant que le chat avec redirection est exécuté.

en supposant que le fichier que vous voulez modifier est my.txt

$cat my.txt    
this is the regular file

Et le fichier que vous souhaitez ajouter est-à-tête

$ cat header
this is the header

Assurez-vous d'avoir une dernière ligne vide dans le fichier d'en-tête.
Maintenant, vous pouvez préfixer avec

$cat header <(cat my.txt) > my.txt

Vous vous retrouvez avec

$ cat my.txt
this is the header
this is the regular file

Autant que je sache, cela ne fonctionne que dans 'bash'.

Lorsque vous commencer à essayer de faire des choses qui deviennent difficiles dans le shell-script, je suggère fortement de regarder dans la réécriture du script dans un "vrai" langage de script (Python/Perl/Ruby/etc)

Comme pour les ajoutant une ligne dans un fichier, il n'est pas possible de le faire par l'intermédiaire de la tuyauterie, comme lorsque vous faites quelque chose comme cat blah.txt | grep something > blah.txt, par inadvertance blancs le fichier.Il y a une petite commande de l'utilitaire appelé sponge vous pouvez l'installer (vous ne cat blah.txt | grep something | sponge blah.txt et il protège le contenu du fichier, puis l'écrit dans le fichier).Il est semblable à un fichier temp, mais vous n'avez pas à le faire explicitement.mais je dirais que c'est un "pire" exigence que, disons, Perl.

Il y a peut être un moyen de le faire via awk, ou similaire, mais si vous avez utiliser le shell-script, je pense qu'un fichier temp est de loin la méthode la plus simple(/seulement?) façon..

EDIT:C'est cassé.Voir Le comportement bizarre lors de l'ajoutant à un fichier avec chat et de la té

La solution de contournement pour le remplacer problème est l'aide de tee:

cat header main | tee main > /dev/null

Comme Daniel Velkov l'indique, l'utilisation té.
Pour moi, c'est simple solution intelligente:

{ echo foo; cat bar; } | tee bar > /dev/null

Celui que j'utilise.Celui-ci vous permet de spécifier l'ordre, supplémentaires caractères, etc ... dans la façon dont vous l'aimez:

echo -e "TEXTFIRSt\n$(< header)\n$(< my.txt)" > my.txt

P. S:seulement ça ne fonctionne pas si les fichiers contenant du texte avec barre oblique inverse, parce qu'il obtient interprétés comme des caractères d'échappement

Surtout pour le fun/coque de golf, mais

ex -c '0r myheader|x' myfile

fera l'affaire, et il n'y a pas de pipelines ou de redirections.Bien sûr, vi/ex n'est pas vraiment pour les non-interactif d'utilisation, afin de vi clignote brièvement.

Pourquoi ne pas simplement utiliser le ed de commande (comme l'a déjà suggéré fluffle ici)?

ed lit tout le fichier en mémoire et exécute automatiquement une modification de fichiers!

Donc, si votre fichier n'est pas énorme ...

# cf. "Editing files with the ed text editor from scripts.",
# http://wiki.bash-hackers.org/doku.php?id=howto:edit-ed

prepend() {
   printf '%s\n' H 1i "${1}" . wq | ed -s "${2}"
}

echo 'Hello, world!' > myfile
prepend 'line to prepend' myfile

Encore une autre solution serait d'utiliser des descripteurs de fichiers ouverts comme suggéré par Jürgen Hötzel dans Rediriger la sortie de sed 's/c/d/' monfichier à myFile

echo cat > manipulate.txt
exec 3<manipulate.txt
# Prevent open file from being truncated:
rm manipulate.txt
sed 's/cat/dog/' <&3 > manipulate.txt

Tout cela pourrait être mis sur une seule ligne, bien sûr.

Une variante sur cb0 la solution pour les "aucun fichier temporaire" pour ajouter du texte fixe:

echo "text to prepend" | cat - file_to_be_modified | ( cat > file_to_be_modified ) 

De nouveau elle s'appuie sur la sous-exécution du shell - la (..) - pour éviter le chat qui refuse d'avoir le même fichier d'entrée et de sortie.

Note:Aimé cette solution.Cependant, dans mon Mac, le fichier original est perdu (la pensée, il ne devrait pas, mais il le fait).Qui pourrait être fixé par écrit votre solution:echo "texte à ajouter le préfixe" | cat - file_to_be_modified | cat > tmp_file;mv tmp_file file_to_be_modified

Voici ce que j'ai découvert:

echo -e "header \n$(cat file)" >file
sed -i -e '1rmyheader' -e '1{h;d}' -e '2{x;G}' myfile

AVERTISSEMENT:ce besoin d'un peu plus de travail pour répondre à l'OP besoins.

Il devrait y avoir une façon de faire de la sed approche par @shixilun travail en dépit de ses réticences.Il doit y avoir une commande bash pour échapper espaces lors de la lecture d'un fichier dans un sed substitution de chaîne (par ex.remplacer les caractères de saut de ligne avec des ' '.Des commandes Shell vis et cat peut traiter avec des caractères non-imprimables, mais pas d'espaces, donc cela ne résoudra pas le cas des OP problème:

sed -i -e "1s/^/$(cat file_with_header.txt)/" file_to_be_prepended.txt

échoue en raison de la crue des retours à la ligne dans le substitut de script, qui doivent être précédées d'un caractère de continuation de ligne () et peut-être suivie par un &, pour garder la coquille et le sed heureux, comme cette SORTE de réponse

sed a une limite de taille de 40K pour les non-global rechercher-remplacer les commandes (pas de fuite /g selon le modèle) ce serait probablement éviter le plus effrayant de la mémoire tampon des problèmes de dépassement de awk anonyme averti de la.

sed -i -e "1s/^/new first line\n/" old_file.txt

Avec $( commande ) vous pouvez écrire la sortie d'une commande dans une variable.Donc je l'ai fait en trois commandes sur une seule ligne et aucun fichier temporaire.

originalContent=$(cat targetfile) && echo "text to prepend" > targetfile && echo "$originalContent" >> targetfile

Si vous avez un gros fichier (quelques centaines de kilo-octets dans mon cas) et l'accès à python, c'est beaucoup plus rapide que cat pipe solutions:

python -c 'f = "filename"; t = open(f).read(); open(f, "w").write("text to prepend " + t)'

Une solution avec printf:

new_line='the line you want to add'
target_file='/file you/want to/write to'

printf "%s\n$(cat ${target_file})" "${new_line}" > "${target_file}"

Vous pouvez aussi faire:

printf "${new_line}\n$(cat ${target_file})" > "${target_file}"

Mais dans ce cas, vous devez être sûr il n'y a pas tout % n'importe où, y compris le contenu du fichier cible, comme cela peut être interprété et vis de vos résultats.

Vous pouvez utiliser perl en ligne de commande:

perl -i -0777 -pe 's/^/my_header/' tmp

Où -je vais créer une ligne de remplacement du fichier et -0777 va siphonner l'ensemble du dossier et faire ^ match que le début.-pe permettra d'imprimer toutes les lignes

Ou si my_header est un fichier:

perl -i -0777 -pe 's/^/`cat my_header`/e' tmp

Où l' /e permettra une eval de code dans la substitution.

current=`cat my_file` && echo 'my_string' > my_file && echo $current >> my_file

où "my_file" est le fichier à ajouter le préfixe "my_string" à.

Je suis aimer @fluffle de l' ed approche le meilleur.Après tout, un outil de ligne de commande vs script de l'éditeur de commandes sont essentiellement la même chose ici;ne voyant pas d'un script de l'éditeur de la solution de la "propreté" soit moindre ou que sais-je encore.

Voici ma ligne de commande annexé à la .git/hooks/prepare-commit-msg pour ajouter un en-repo .gitmessage fichier de messages de validation:

echo -e "1r $PWD/.gitmessage\n.\nw" | ed -s "$1"

Exemple .gitmessage:

# Commit message formatting samples:
#       runlevels: boot +consolekit -zfs-fuse
#

Je suis en train de faire 1r au lieu de 0r, car qui sera de quitter le vide de prêt-à-écrire en ligne sur le fichier à partir du modèle d'origine.Ne pas mettre une ligne vide au-dessus de votre .gitmessage ensuite, vous allez vous retrouver avec deux lignes vides. -s supprime les informations de diagnostic de sortie de l'ed.

Dans le cadre de parcourir ce, je découvert que pour vim-buffs il est également bon d'avoir:

[core]
        editor = vim -c ':normal gg'

variables, ftw?

NEWFILE=$(echo deb http://mirror.csesoc.unsw.edu.au/ubuntu/ $(lsb_release -cs) main universe restricted multiverse && cat /etc/apt/sources.list)
echo "$NEWFILE" | sudo tee /etc/apt/sources.list

Je pense que c'est le plus propre de la variation de l'ed:

cat myheader | { echo '0a'; cat ; echo -e ".\nw";} | ed myfile

comme une fonction:

function prepend() { { echo '0a'; cat ; echo -e ".\nw";} | ed $1; }

cat myheader | prepend myfile

Si vous êtes de script en BASH, en fait, vous pouvez simplement question:

cat - yourfile  /tmp/out && mv /tmp/out yourfile

C'est en fait dans le Complexe Exemple vous avez vous-même publié dans votre propre question.

À mon humble avis il n'y a pas de shell solution (et ne sera jamais une) qui fonctionne de manière fiable et quelle que soit la taille des deux fichiers myheader et myfile.La raison en est que si vous voulez le faire sans récurrents dans un fichier temporaire (et sans laisser la coquille se reproduire en silence dans un fichier temporaire, par exemplegrâce à des constructions telles que exec 3<>myfile, de la tuyauterie à tee, etc.

La "vraie" solution vous êtes à la recherche pour les besoins de jouer avec le système de fichiers, et il n'est donc pas disponible dans l'espace utilisateur et serait dépend de la plateforme:vous demandez de modifier le système de fichiers pointeur en cours d'utilisation par myfile à la valeur actuelle du système de fichiers pointeur pour myheader et de les remplacer dans le système de fichiers de l' EOF de myheader avec une relation de l'actuel système de fichiers de l'adresse pointée par myfile.Ce n'est pas anodin et, évidemment, ne peut pas être fait par un non-super-utilisateur, et probablement pas par le super-utilisateur, soit...Jouer avec les inodes, etc.

Vous pouvez plus ou moins faux ce à l'aide de dispositifs de boucle, si.Voir, par exemple, ce fil.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top