Comment ajouter du texte au début d'un fichier dans Bash?

285

Bonjour, je veux ajouter du texte à un fichier. Par exemple, je veux ajouter des tâches au début d'un fichier todo.txt. Je suis au courant echo 'task goes here' >> todo.txtmais cela ajoute la ligne à la fin du fichier (pas ce que je veux).

utilisateur479534
la source
2
Il si aucun moyen efficace de le faire pour des fichiers volumineux: unix.stackexchange.com/questions/87772/...
Ciro Santilli新疆改造中心法轮功六四事件
@ auriez-vous jeter un coup d'œil à cette méthode superuser.com/a/1352628/11116
Evan Carroll

Réponses:

374
echo 'task goes here' | cat - todo.txt > temp && mv temp todo.txt

ou

sed -i '1s/^/task goes here\n/' todo.txt

ou

sed -i '1itask goes here' todo.txt
Dennis Williamson
la source
4
le premier fonctionne très bien! cela vous dérangerait-il d'expliquer la logique? Je ne suis pas particulièrement sûr de savoir comment interpréter la syntaxe.
user479534
44
@ user8347: Pipe ( |) le message ( echo '...') catauquel utilise -(entrée standard) le premier fichier et todo.txtle second. catconCATenates plusieurs fichiers. Envoyez la sortie ( >) dans un fichier nommé temp. S'il n'y a pas d'erreur ( &&), catrenommez ( mv) le tempfichier dans le fichier d'origine ( todo.txt).
Dennis Williamson
1
@itaifrenkel: Il faudrait que je voie ce que vous avez fait, mais s'il catreçoit une barre oblique inverse littérale n, il ne le convertira pas en une nouvelle ligne. Quelque chose d'autre a dû faire ça. Au lieu de cat, essayez de siffler hexdump -Cpour voir si vous envoyez réellement une barre oblique inverse et n ou s'il s'agit d'une nouvelle ligne. Vous pouvez également essayer cat -ed’afficher les fins de ligne.
Dennis Williamson
1
L'utilisation de 2 et 3 (3 me semble plus simple) vous permet d'ajouter du texte à plusieurs fichiers à la fois.
Félix
4
@Kira: Les 1moyens ne font la prochaine commande que sur la première ligne du fichier et la icommande est insert. Recherchez dans la page de manuel sous la section "Adresses" et dans la section "Commandes à zéro ou une adresse".
Dennis Williamson
73

Une option plus simple à mon avis est:

echo -e "task goes here\n$(cat todo.txt)" > todo.txt

Cela fonctionne car la commande à l'intérieur de $(...)est exécutée avant d' todo.txtêtre écrasée par> todo.txt

Alors que les autres réponses fonctionnent bien, je trouve cela beaucoup plus facile à retenir parce que j'utilise écho et chat tous les jours.

EDIT: Cette solution est une très mauvaise idée s’il ya des barres obliques inverses todo.txt, car grâce à l’ -eécho du drapeau, elles seront interprétées. Un autre moyen, beaucoup plus simple, de placer des nouvelles lignes dans la chaîne de préface est ...

echo "task goes here
$(cat todo.txt)" > todo.txt

... simplement pour utiliser les nouvelles lignes. Bien sûr, ce n'est plus un one-liner, mais de manière réaliste, ce n'était pas non plus un one-liner auparavant. Si vous faites cela dans un script et que vous craignez d'indenter (par exemple, vous l'exécutez dans une fonction), il existe quelques solutions de contournement pour que cela reste bien ajusté, y compris, mais sans s'y limiter:

(echo 'task goes here' && cat todo.txt) > todo.txt
echo 'task goes here'$'\n'"$(cat todo.txt)" > todo.txt

De même, si vous vous souciez de savoir si une nouvelle ligne est ajoutée à la fin de todo.txt, n'utilisez pas ces options. Eh bien, sauf l'avant-dernier. Cela ne plaisante pas avec la fin.

John Alberts
la source
1
Je n'ai pas du tout exécuté $ (...).
SCL
2
Cela pourrait fonctionner mieux (ou pas du tout) avec des guillemets doubles au lieu de simples ...
Message
5
Ne -econvertira- t-il pas également les séquences d'échappement dans todo.txt?
mk12
2
Solutions de contournement céder -> cat: <nom du fichier de destination>: le fichier d'entrée est le fichier de sortie ...
ici, le
printf serait beaucoup plus cohérent sur toutes les plates-formes et devrait en général fonctionner plus facilement qu'écho
Peter Berg
28

Ils moreutilsont un bel outil appelé sponge:

echo "task goes here" | cat - todo.txt | sponge todo.txt

Cela va "absorber" STDIN et ensuite écrire dans le fichier, ce qui signifie que vous n'avez pas à vous soucier des fichiers temporaires et de les déplacer.

Vous pouvez utiliser moreutilsde nombreuses distributions Linux, via apt-get install moreutilsou sous OS X, avec Homebrew , avec brew install moreutils.

slhck
la source
(echo 'ble'; cat todo.txt)
J'irais
11

Vous pouvez utiliser Vim en mode Ex:

ex -s -c '1i|task goes here' -c x todo.txt
  1. 1 sélectionner la première ligne

  2. i insérer

  3. x sauver et fermer

Steven Penny
la source
5

Vous pouvez créer un nouveau fichier temporaire.

echo "new task" > new_todo.txt
cat todo.txt >> new_todo.txt
rm todo.txt
mv new_todo.txt todo.txt

Vous pouvez également utiliser sedou awk. Mais fondamentalement, la même chose se produit.

Keith
la source
1
Supposons que vous manquiez d’espace disque, ce qui new_todo.txtn’est écrit que partiellement. Votre solution semble perdre le fichier d'origine.
NPE
Qui manque d'espace disque? ;-) C'est juste un exemple simple.
Keith
2
@ Keith Quelqu'un travaillant sur une machine virtuelle qui ne s'attendait pas à avoir besoin d'un lecteur virtuel particulièrement volumineux. Ou quelqu'un qui déplace un gros fichier. Dans tous les cas, le véritable argument contre cela est les permissions de répertoire; Si vous n'êtes pas autorisé à créer de nouveaux fichiers dans le répertoire indiqué, la seule commande qui sera exécutée avec succès dans votre script est celle rmdu fichier d'origine.
Parthian Shot
3

Si le fichier texte est suffisamment petit pour tenir en mémoire, vous n'avez pas besoin de créer un fichier temporaire pour le remplacer. Vous pouvez tout charger en mémoire et l'écrire dans le fichier.

echo "$(echo 'task goes here' | cat - todo.txt)" > todo.txt

Il est impossible d'ajouter des lignes au début du fichier sans écraser le fichier entier.

Rucent88
la source
Juste pour poser la question évidente: où est la limite de caractères des variables de shell?
Nixda
Autant que je sache, il n’est limité que par la quantité de mémoire disponible. J'ai rempli plus de 100 Mo de variables en mémoire. text=$(cat file). Veillez toutefois à n'utiliser que du texte, car les variables du shell ne sont pas des fichiers
Rucent88
2

Vous ne pouvez pas insérer de contenu au début d'un fichier. La seule chose à faire est de remplacer le contenu existant ou d'ajouter des octets après la fin du fichier en cours.

Toute solution à votre question nécessite alors la création d’un fichier temporaire (ou tampon) (sur la mémoire ou sur le disque) qui écrasera le fichier original.

Veillez à ne pas perdre de données en préservant le fichier d'origine lors de la création du nouveau, si le système de fichiers était saturé au cours du processus. par exemple:

cat <(echo task go there) todo.txt > todo.txt.new && mv todo.txt.new todo.txt
jlliagre
la source
Les votants sont les bienvenus pour expliquer leur motivation. Aucune des réponses restantes, y compris celle acceptée, ne contredit quoi que ce soit dans ma réponse.
jeudi
C’est difficile à analyser car les <...> ressemblent à des crochets, ce qui, je suppose, ne le sont pas. Un espace entre le <et le (pourrait aider?)
dumbledad
Cela ne fonctionne pas pour moi. echo HOME=\"/g/Users/timregan/\" | cat - 'F:\Program Files\Git\etc\profile'fonctionne mais cat <echo HOME=\"/g/Users/timregan/\" 'F:\Program Files\Git\etc\profile'donne l’erreur "echo: Aucun fichier ou répertoire de ce type"
dumbledad
@ Dumbledad Vous pensez trop à ma réponse. Vous n'avez rien à analyser. Un espace entre le <et le (briserait la syntaxe. Essayezcat <(echo HOME=\"/g/Users/timregan/\") 'F:\Program Files\Git\etc\profile'
Jlliagre
1

Vous pouvez utiliser tee:

echo 'task goes here' | cat - todo.txt | tee todo.txt
Radu Rădeanu
la source
3
Non, vous ne pouvez pas askubuntu.com/a/752451
Steven Penny
0

GitBash + Windows10 + Multline :

Voici une version qui vous permet d’utiliser des chaînes multilignes .

##############################################
## This section for demo purpose only,      ##
## So you can save entire file as           ##
## whatever.sh and run it.                  ##
##                                          ##
##############################################
> MY_TARGET_FILE.txt ##Make Or Clear File
echo "[STARTER_CONTENT]" >> MY_TARGET_FILE.txt
##############################################

## Below is main code:

##################################################
TARGET_FILE_VARIABLE="MY_TARGET_FILE.txt"
ADD_TO_HEAD_VARIABLE=$(cat << "HEREDOC_HEAD_TEXT"
//|  +-------------------------------------+   |//
//|  |                                     |   |//
//|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
//|  |                                     |   |//
//|  +-------------------------------------+   |//
HEREDOC_HEAD_TEXT
)
##################################################
TAR=$TARGET_FILE_VARIABLE                       ##
TEX=$ADD_TO_HEAD_VARIABLE                       ##
echo "$TEX" | cat - $TAR > TEMP && mv TEMP $TAR ##
##################################################

## Expected contents of MY_TARGET_FILE.txt :
## //|  +-------------------------------------+   |//
## //|  |                                     |   |//
## //|  |     MESSAGE_FOR_HEAD_OF_FILE        |   |//
## //|  |                                     |   |//
## //|  +-------------------------------------+   |//
## [STARTER_CONTENT]
J MADISON
la source