sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Je m'attends à ce que ce sed
script insère un tab
devant chaque ligne, $filename
mais ce n'est pas le cas. Pour une raison quelconque, il insère un t
fichier.
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Je m'attends à ce que ce sed
script insère un tab
devant chaque ligne, $filename
mais ce n'est pas le cas. Pour une raison quelconque, il insère un t
fichier.
Réponses:
Toutes les versions de sed
comprennent \t
. Insérez simplement une tabulation littérale à la place (appuyez sur Ctrl- Vpuis Tab).
\t
dans la partie de remplacement de l'expression (il est reconnu \t
dans la partie de correspondance de motif très bien)
En utilisant Bash, vous pouvez insérer un caractère TAB par programme comme ceci:
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
$'string'
explication mais manquez. En fait, je soupçonne, en raison de l'utilisation extrêmement maladroite que vous avez probablement une compréhension incomplète (comme la plupart d'entre nous le font avec bash). Voir mon explication ci-dessous: stackoverflow.com/a/43190120/117471
$TAB
les guillemets simples, vous devrez donc les utiliser entre guillemets doubles.
*
des guillemets doubles à l'intérieur ... cela sera traité comme un glob, pas comme l'expression régulière que vous souhaitez.
@sedit était sur le bon chemin, mais il est un peu difficile de définir une variable.
La façon de faire cela dans bash est de mettre un signe dollar devant votre chaîne entre guillemets simples.
$ 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 une extension de variable, vous pouvez mettre les chaînes entre guillemets comme ceci:
$ 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 que la plupart d' entre nous attendent lorsque nous utilisons des choses comme \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 $ 'string' sont traités spécialement. Le mot se développe en chaîne , avec les caractères d'échappement par barre oblique inverse remplacés comme spécifié par la norme ANSI C. Les séquences d'échappement de backslash, si présentes, sont décodées ...
Le résultat développé est entre guillemets simples, comme si le signe dollar n’était pas présent.
Personnellement, je pense que la plupart des efforts pour éviter les bash sont ridicules, car éviter les bashismes ne rend PAS votre code portable. (Votre code sera moins fragile si vous le limitez bash -eu
que si vous essayez d'éviter de bash et d'utiliser sh
[sauf si vous êtes un ninja POSIX absolu].) Mais plutôt que d'avoir un argument religieux à ce sujet, je vais juste vous donner le MEILLEUR * répondre.
$ 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 scripts shell anti-bash feraient de mal dans leur code est l'utilisation echo '\t'
comme dans la réponse de @ robrecord . Cela fonctionnera pour l'écho GNU, mais pas pour l'écho BSD. Cela est expliqué par The Open Group à http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 Et ceci est un exemple de pourquoi essayer d'éviter les bashismes échoue généralement.
J'ai utilisé quelque chose comme ça avec un shell Bash sur Ubuntu 12.04 (LTS):
Pour ajouter une nouvelle ligne avec tabulation, en second lieu lorsque la première correspond:
sed -i '/first/a \\t second' filename
Pour remplacer d' abord par tabulation, ensuite :
sed -i 's/first/\\t second/g' filename
\\t
et non \t
.
Utilisez $(echo '\t')
. Vous aurez besoin de citations autour du motif.
Par exemple. Pour supprimer un onglet:
sed "s/$(echo '\t')//"
echo '\t'
va produire 2 caractères séparés. Le moyen portable POSIX est d'utiliser printf '\t'
. C'est pourquoi je dis: n'essayez pas de rendre votre code portable en n'utilisant pas bash. C'est plus dur que tu ne le penses. L'utilisation bash
est la chose la plus portable que la plupart d'entre nous puissent faire.
Vous n'avez pas besoin d'utiliser sed
pour faire une substitution alors qu'en fait, 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 car ce n'est pas une expression régulière.
par exemple en utilisant awk
awk '{print "\t"$0}' $filename > temp && mv temp $filename
sed
ne prend pas en charge \t
, ni d'autres séquences d'échappement comme \n
d'ailleurs. Le seul moyen que j'ai trouvé pour le faire était d'insérer le caractère de tabulation dans le script en utilisantsed
.
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 expressions rationnelles de 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 __name__ == '__main__':
main(sys.argv[1:])
Au lieu de BSD sed, j'utilise perl:
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
hi
Je pense que d' autres ont permis de clarifier ce suffisamment pour d' autres approches ( sed
, AWK
, etc.). Cependant, mes bash
réponses spécifiques (testées sur macOS High Sierra et CentOS 6/7) suivent.
1) Si OP voulait utiliser une méthode de recherche et de remplacement similaire à ce qu'il avait proposé à l'origine, je suggérerais d'utiliser perl
pour cela, comme suit. Notes: les barres obliques inverses avant les parenthèses pour les regex ne devraient pas être nécessaires, et cette ligne de code reflète comment il $1
est préférable de l'utiliser \1
qu'avec perl
un opérateur de substitution (par exemple, selon la documentation Perl 5 ).
perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) Cependant, comme l'a souligné ghostdog74 , puisque l'opération souhaitée est en fait d' ajouter simplement un onglet au début de chaque ligne avant de changer le fichier tmp en fichier d'entrée / cible ( $filename
), je recommanderais à perl
nouveau mais avec la modification 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 `` en place '' (ajouter un -i
drapeau) et de simplifier les choses en un one-liner plus élégant avec
perl -i -pe $'s/^/\t/' $filename