sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
J'attends de ce script sed qu'il insère une tabulation dans la police de chaque ligne dans $filename
, mais ce n'est pas le cas. Pour une raison quelconque, il insère un t à la place .. Étrange ..
Toutes les versions de sed
ne comprennent pas \t
. Insérez simplement un onglet littéral à la place (appuyez sur Ctrl-V puis Tab).
En utilisant Bash, vous pouvez insérer un caractère de tabulation par programme de la manière suivante:
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
@sedit était sur le bon chemin, mais définir une variable est un peu délicat.
La façon de faire cela en bash est d’utiliser un signe dollar devant votre chaîne citée.
$ echo -e '1\n2\n3'
1
2
3
$ echo -e '1\n2\n3' | sed 's/.*/\t&/g'
t1
t2
t3
$ echo -e '1\n2\n3' | sed $'s/.*/\t&/g'
1
2
3
Si votre chaîne doit inclure le développement de variable, vous pouvez regrouper les chaînes entre guillemets de la manière suivante:
$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958 1
1491237958 2
1491237958 3
Dans bash $'string'
provoque "l'expansion ANSI-C". Et c'est ce à quoi la plupart d'entre nous s'attendons lorsque nous utilisons des éléments tels que \t
, \r
, \n
, etc. De: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC -Quoting
Les mots de la forme $ 'chaîne' sont traités spécialement. La Parole se développe to string, avec les caractères d'échappement avec une barre oblique inversée remplacés comme spécifié par la norme ANSI C. Les séquences d'échappement avec une barre oblique inversée, si elles sont présentes, sont décodé ...
Le résultat étendu est indiqué entre guillemets simples, comme si le signe dollar n'avait pas été été présent.
Personnellement, je pense que la plupart des efforts pour éviter bash sont stupides, car éviter les bashismes ne rend * PAS votre code portable. (Votre code sera moins fragile si vous le réduisez en bash -eu
plutôt que si vous essayez d'éviter bash et utilisez sh
[à moins que vous ne soyez un ninja POSIX absolu].) Mais plutôt que d'avoir un argument religieux à ce sujet, je vous donnerai simplement la MEILLEURE * réponse.
$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
1
2
3
* Meilleure réponse? Oui, car un exemple de ce que la plupart des scripteurs de Shell anti-bash feraient mal dans leur code est d'utiliser echo '\t'
comme dans la réponse de @ robrecord . Cela fonctionnera pour GNU echo, mais pas pour BSD. Ceci est expliqué par The Open Group à http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 C'est un exemple de la raison pour laquelle les tentatives d'éviter les bashismes échouent généralement.
J'ai utilisé quelque chose comme ceci avec un shell Bash sur Ubuntu 12.04 (LTS):
Pour ajouter une nouvelle ligne avec tab, deuxième lorsque premier correspond:
sed -i '/first/a \\t second' filename
Pour remplacer premier avec onglet, deuxième :
sed -i 's/first/\\t second/g' filename
Utilisez $(echo '\t')
. Vous aurez besoin de citations autour du motif.
Par exemple. Pour supprimer un onglet:
sed "s/$(echo '\t')//"
Vous n'avez pas besoin d'utiliser sed
pour effectuer une substitution, vous voulez simplement insérer une tabulation devant la ligne. La substitution pour ce cas est une opération coûteuse par rapport à la simple impression, surtout lorsque vous travaillez avec de gros fichiers. C'est plus facile à lire aussi que ce n'est pas une regex.
par exemple en utilisant awk
awk '{print "\t"$0}' $filename > temp && mv temp $filename
Au lieu de BSD sed, j'utilise Perl:
ct@MBA45:~$ python -c "print('\t\t\thi')" |Perl -0777pe "s/\t/ /g"
hi
sed
ne supporte pas \t
, pas plus que d'autres séquences d'échappement comme \n
. La seule façon que j'ai trouvée de le faire était d'insérer le caractère de tabulation dans le script en utilisant sed
.
Cela dit, vous pouvez envisager d’utiliser Perl ou Python. Voici un court script Python que j'ai écrit et que j'utilise pour toutes les regex des flux:
#!/usr/bin/env python
import sys
import re
def main(args):
if len(args) < 2:
print >> sys.stderr, 'Usage: <search-pattern> <replace-expr>'
raise SystemExit
p = re.compile(args[0], re.MULTILINE | re.DOTALL)
s = sys.stdin.read()
print p.sub(args[1], s),
if __== '__main__':
main(sys.argv[1:])
Je pense que d'autres ont clarifié cela de manière adéquate pour d'autres approches (sed
, AWK
, etc.). Cependant, mes réponses bash
- spécifiques (testées sur macOS High Sierra et CentOS 6/7) suivent.
1) Si OP souhaitait utiliser une méthode de recherche-remplacement similaire à celle proposée à l'origine, je suggérerais d'utiliser Perl
pour cela, comme suit. Notes: les barres obliques inverses avant les parenthèses pour les expressions rationnelles ne devraient pas être nécessaires, et cette ligne de code indique comment il vaut mieux utiliser $1
que \1
avec l'opérateur de substitution Perl
(par exemple, per Perl 5 documentation ).
Perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) Cependant, comme indiqué par ghostdog74 , puisque l’opération désirée consiste en fait à simplement ajouter un onglet au début de chaque ligne avant de remplacer le fichier tmp par le fichier en entrée/cible ($filename
), Je recommanderais à nouveau Perl
mais avec la ou les modification (s) suivante (s):
Perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
Perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
3) Bien sûr, le fichier tmp est superflu, il est donc préférable de tout faire «à la place» (en ajoutant le drapeau -i
) et de simplifier les choses pour en faire un one-liner plus élégant avec
Perl -i -pe $'s/^/\t/' $filename