Existe-t-il une commande Unix pour ajouter des chaînes de caractères dans un fichier texte?
Quelque chose comme:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Existe-t-il une commande Unix pour ajouter des chaînes de caractères dans un fichier texte?
Quelque chose comme:
prepend "to be prepended" text.txt
<<(echo "to be prepended") < text.txt | sponge text.txt
Réponses:
sed -i.old '1s;^;to be prepended;' inFile
-i
écrit le changement en place et effectue une sauvegarde si une extension est donnée. (Dans ce cas, .old
)1s;^;to be prepended;
remplace le début de la première ligne par la chaîne de remplacement donnée, en utilisant ;
comme délimiteur de commande.\n
après le préfixe; en fonction de leurs besoins. Solution soignée.
inFile
Les répertoires inclus dans son chemin peuvent-ils être inclus?
\n
. J'aurais dû lire les commentaires en premier. Zut.
'1s;^;my-prepended-line\;\n;'
printf '%s\n%s\n' "to be prepended" "$(cat text.txt)" >text.txt
git config --get-regex $arg | sed -r 's/\t{3}/\\n/g';
et cela gâche car il convertit le \t
et \n
.
echo "to be prepended"$'\n'"$(cat text.txt)"
Je suis surpris que personne n'ait mentionné cela.
cat <(echo "before") text.txt > newfile.txt
ce qui est sans doute plus naturel que la réponse acceptée (imprimer quelque chose et le faire passer dans une commande de substitution est contre-intuitif lexicographiquement).
... et détournant ce que Ryan a dit ci-dessus, sponge
vous n'avez pas besoin d'un fichier temporaire:
sudo apt-get install moreutils
<<(echo "to be prepended") < text.txt | sponge text.txt
EDIT: On dirait que cela ne fonctionne pas dans Bourne Shell /bin/sh
En utilisant une chaîne ici - <<<
, vous pouvez faire:
<<< "to be prepended" < text.txt | sponge text.txt
<<(echo "to be prepended") < text.txt
et vos <<< "to be prepended" < text.txt
constructions ne fonctionnent pas en bash; ils nécessitent zsh.
Voici une possibilité:
(echo "to be prepended"; cat text.txt) > newfile.txt
vous ne pourrez probablement pas contourner facilement un fichier intermédiaire.
Alternatives (peuvent être lourdes avec l'échappement du shell):
sed -i '0,/^/s//to be prepended/' text.txt
cat <(echo "to be prepended") text.txt > newfile.txt
. À bien y penser, je ne suis pas sûr que le mien soit lié, alors je poste une réponse séparée.
Cela fonctionnera pour former la sortie. Le - signifie une entrée standard, qui est fournie via le tuyau de l'écho.
echo -e "to be prepended \n another line" | cat - text.txt
Pour réécrire le fichier, un fichier temporaire est requis car il ne peut pas être redirigé vers le fichier d'entrée.
echo "to be prepended" | cat - text.txt > text.txt.tmp
mv text.txt.tmp text.txt
text.txt
comme demandé, mais l'affiche sur stdout. La sortie pourrait être canalisée dans un fichier différent si cela fonctionne pour l'OP
Préfère la réponse d'Adam
Nous pouvons faciliter l'utilisation de l' éponge . Maintenant, nous n'avons pas besoin de créer un fichier temporaire et de le renommer en
echo -e "to be prepended \n another line" | cat - text.txt | sponge text.txt
Remarque:
Cela peut avoir des effets secondaires inattendus, notamment le remplacement potentiel d'un lien symbolique par un fichier normal, se retrouver avec des autorisations différentes sur le fichier et modifier la date de création (naissance) du fichier.
sed -i
, comme dans la réponse du prince John Wesley , tente au moins de restaurer les autorisations d'origine, mais les autres limitations s'appliquent également.
Voici une alternative simple qui utilise un fichier temporaire (cela évite de lire le fichier d'entrée entier en mémoire comme le fait la solution de Shime ):
{ printf 'to be prepended'; cat text.txt; } > tmp.txt && mv tmp.txt text.txt
L'utilisation d'une commande de groupe ( { ...; ...; }
) est légèrement plus efficace que l'utilisation d'un sous - shell ( (...; ...)
), comme dans la solution de 0xC0000022L .
Les avantages sont:
Il est facile de contrôler si le nouveau texte doit être directement ajouté à la première ligne ou s'il doit être inséré en tant que nouvelle (s) ligne (s) (ajoutez simplement \n
à l' printf
argument).
Contrairement à la sed
solution, cela fonctionne si le fichier d'entrée est vide ( 0
octets).
La sed
solution peut être simplifiée si l'intention est d'ajouter au début une ou plusieurs lignes entières au contenu existant (en supposant que le fichier d'entrée n'est pas vide):
sed
La i
fonction de insère des lignes entières:
Avec GNU sed
:
# Prepends 'to be prepended' *followed by a newline*, i.e. inserts a new line.
# To prepend multiple lines, use '\n' as part of the text.
# -i.old creates a backup of the input file with extension '.old'
sed -i.old '1 i\to be prepended' inFile
Une variante portable qui fonctionne également avec macOS / BSD sed
:
# Prepends 'to be prepended' *followed by a newline*
# To prepend multiple lines, escape the ends of intermediate
# lines with '\'
sed -i.old -e '1 i\
to be prepended' inFile
Notez que le saut de ligne littéral après le \
est obligatoire.
Utilisation du vénérable ed
utilitaire POSIX :
Remarque:
ed
lit invariablement le fichier d'entrée dans son ensemble en mémoire en premier.Pour ajouter directement à la première ligne (comme avec sed
, cela ne fonctionnera pas si le fichier d'entrée est complètement vide ( 0
octets)):
ed -s text.txt <<EOF
1 s/^/to be prepended/
w
EOF
-s
ed
messages d'état supprimés .ed
sous forme de document here-document ( <<EOF\n...\nEOF
) sur plusieurs lignes , c'est-à-dire via stdin ; par défaut, l'expansion des chaînes est effectuée dans ces documents (les variables shell sont interpolées); citez le délimiteur d'ouverture pour supprimer cela (par exemple,<<'EOF'
).1
fait de la 1ère ligne la ligne courantes
effectue une substitution de chaîne basée sur une expression régulière sur la ligne courante, comme dans sed
; vous pouvez inclure des sauts de ligne littéraux dans le texte de substitution, mais ils doivent être \
échappés.w
réécrit le résultat dans le fichier d'entrée (pour le test, remplacez w
par ,p
pour imprimer uniquement le résultat, sans modifier le fichier d'entrée).Pour ajouter une ou plusieurs lignes entières au début :
Comme avec sed
, la i
fonction ajoute invariablement une nouvelle ligne à la fin du texte à insérer.
ed -s text.txt <<EOF
0 i
line 1
line 2
.
w
EOF
0 i
fait 0
(le début du fichier) la ligne courante et démarre le mode insertion ( i
); notez que les numéros de ligne sont 1
basés sur une autre base..
sur sa propre ligne.Probablement rien de intégré, mais vous pouvez écrire le vôtre assez facilement, comme ceci:
#!/bin/bash
echo -n "$1" > /tmp/tmpfile.$$
cat "$2" >> /tmp/tmpfile.$$
mv /tmp/tmpfile.$$ "$2"
Quelque chose comme ça au moins ...
$$
est cependant insuffisante pour le code de production (attaque de lien symbolique google); mais c'est certainement mieux qu'un nom de fichier statique.
mktemp
Dans certaines circonstances, le texte préfixé peut être disponible uniquement à partir de stdin. Ensuite, cette combinaison fonctionnera.
echo "to be prepended" | cat - text.txt | tee text.txt
Si vous souhaitez omettre la tee
sortie, ajoutez > /dev/null
.
tee
ne clobe pas text.txt
avant cat
de le lire? Je ne pense pas - ce qui rendrait cette solution dangereuse pour la santé du dossier.
lenA=1000000; yes a | head -c $lenA > a.txt; lenB=10000; b=$(yes b | head -c $lenB); echo "$b" | cat - a.txt | tee a.txt > /dev/null
. Si lenA
vaut 1000000 (fichier de 1 Mo) et lenB
10000 (texte de 10 Ko en préfixe), alors le fichier "a.txt" est écrasé par 20 Ko de lettres "b". C'est totalement cassé. Maintenant, si vous utilisez 1Mb a.txt et 1Mb de texte à ajouter, tee
entre dans une boucle générant un fichier 7Gb +, j'ai dû arrêter la commande. Il est donc évident que le résultat est imprévisible pour les grandes tailles. Je n'ai aucune information si cela devrait fonctionner sur de petites tailles.
Solution:
printf '%s\n%s' 'text to prepend' "$(cat file.txt)" > file.txt
Notez que cela est sûr sur tous les types d'entrées, car il n'y a pas d'extensions. Par exemple, si vous souhaitez ajouter un préfixe !@#$%^&*()ugly text\n\t\n
, cela fonctionnera simplement:
printf '%s\n%s' '!@#$%^&*()ugly text\n\t\n' "$(cat file.txt)" > file.txt
La dernière partie à considérer est la suppression des espaces à la fin du fichier lors de la substitution de commande "$(cat file.txt)"
. Toutes les solutions de contournement pour cela sont relativement complexes. Si vous souhaitez conserver les nouvelles lignes à la fin de file.txt, voir ceci: https://stackoverflow.com/a/22607352/1091436
file.txt
est plus grand que ce qui peut être inséré dans la liste d'arguments printf
.
Une autre façon d'utiliser sed
:
sed -i.old '1 {i to be prepended
}' inFile
Si la ligne à ajouter est multiligne:
sed -i.old '1 {i\
to be prepended\
multiline
}' inFile
sed -i '1ito be prepended' inFile
- ou est-ce uniquement autorisé pour GNU sed?
sed
, la i
commande est suivie d'une barre oblique inverse et d'une nouvelle ligne, et chaque ligne d'entrée sauf la dernière se termine également par une barre oblique inverse. GNU sed
autorise les raccourcis dans le sens que vous demandez, mais ce n'est que GNU sed
qui le fait. '
Comme testé dans Bash (dans Ubuntu), si vous démarrez avec un fichier de test via;
echo "Original Line" > test_file.txt
vous pouvez exécuter;
echo "$(echo "New Line"; cat test_file.txt)" > test_file.txt
ou, si la version de bash est trop ancienne pour $ (), vous pouvez utiliser des backticks;
echo "`echo "New Line"; cat test_file.txt`" > test_file.txt
et recevez le contenu suivant de "test_file.txt";
New Line
Original Line
Pas de fichier intermédiaire, juste bash / echo.
Une autre solution assez simple est:
$ echo -e "string\n" $(cat file)
cat
expansion des paramètres entre guillemets doubles est une très bonne raison pour un vote défavorable . Ce code divise le contenu du fichier en mots et passe chacun de ces mots comme argument distinct à echo
. Vous perdez les limites des arguments d'origine, vous perdez les nouvelles lignes / tabulations / etc., et les chaînes comme \t
et \n
dans le texte d'origine sont remplacées par des tabulations et des nouvelles lignes au lieu d'être conservées telles quelles.
Si vous aimez vi / vim, c'est peut-être plus votre style.
printf '0i\n%s\n.\nwq\n' prepend-text | ed file
Je recommanderais de définir une fonction, puis de l'importer et de l'utiliser si nécessaire.
prepend_to_file() {
file=$1
text=$2
if ! [[ -f $file ]] then
touch $file
fi
echo "$text" | cat - $file > $file.new
mv -f $file.new $file
}
Ensuite, utilisez-le comme ceci:
prepend_to_file test.txt "This is first"
prepend_to_file test.txt "This is second"
Le contenu de votre fichier sera alors:
This is second
This is first
Je suis sur le point d'utiliser cette approche pour implémenter un programme de mise à jour du journal des modifications.