sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Mi aspetto che questo sedscript inserisca un tabdavanti a ogni riga, $filenamema non lo è. Per qualche motivo sta inserendo tinvece un file .
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Mi aspetto che questo sedscript inserisca un tabdavanti a ogni riga, $filenamema non lo è. Per qualche motivo sta inserendo tinvece un file .
Risposte:
Non tutte le versioni di sedcapire \t. Basta inserire invece una tabulazione letterale (premere Ctrl- Vquindi Tab).
\tnella parte sostitutiva dell'espressione (riconosciuta \tnella parte del pattern matching benissimo)
Usando Bash puoi inserire un carattere di tabulazione a livello di codice in questo modo:
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
$'string'spiegazione ma manca. In effetti sospetto, a causa dell'uso estremamente imbarazzante che probabilmente hai una comprensione incompleta (come la maggior parte di noi fa con bash). Vedere la mia spiegazione di seguito: stackoverflow.com/a/43190120/117471
$TABvirgolette singole, quindi dovrai usarle virgolette doppie.
*virgolette doppie ... questo verrà trattato come un glob, non come la regex che intendi.
@sedit era sulla strada giusta, ma è un po 'imbarazzante definire una variabile.
Il modo per farlo in bash è mettere un segno di dollaro davanti alla singola stringa tra virgolette.
$ 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
Se la tua stringa deve includere l'espansione della variabile, puoi mettere insieme le stringhe tra virgolette in questo modo:
$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958 1
1491237958 2
1491237958 3
In bash $'string'causa "l'espansione ANSI-C". E questo è ciò che la maggior parte di noi si aspettano quando usiamo le cose come \t, \r, \n, ecc Da: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting
Le parole nella forma $ "stringa" vengono trattate in modo speciale. La parola si espande in stringa , con caratteri di escape con barra rovesciata sostituiti come specificato dallo standard ANSI C. Le sequenze di escape backslash, se presenti, vengono decodificate ...
Il risultato espanso è a virgolette singole, come se il segno del dollaro non fosse presente.
Personalmente penso che la maggior parte degli sforzi per evitare il bash siano sciocchi perché evitare i bashismi NON * rende il tuo codice portabile. (Il tuo codice sarà meno fragile se lo fai, bash -eupiuttosto che se cerchi di evitare bash e usare sh[a meno che tu non sia un ninja POSIX assoluto].) Ma invece di avere una discussione religiosa su questo, ti darò solo il MEGLIO * risposta.
$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
1
2
3
* Migliore risposta? Sì, perché un esempio di ciò che la maggior parte degli script di shell anti-bash farebbe di sbagliato nel loro codice è l'uso echo '\t'come nella risposta di @ robrecord . Questo funzionerà per GNU echo, ma non per BSD echo. Ciò è spiegato da The Open Group su http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 E questo è un esempio del perché il tentativo di evitare i bashismi di solito fallisce.
Ho usato qualcosa di simile con una shell Bash su Ubuntu 12.04 (LTS):
Per aggiungere una nuova riga con tabulazione, la seconda quando viene trovata la prima :
sed -i '/first/a \\t second' filename
Per sostituire il primo con la tabulazione, il secondo :
sed -i 's/first/\\t second/g' filename
\\te non \t.
Usa $(echo '\t'). Avrai bisogno di virgolette attorno allo schema.
Per esempio. Per rimuovere una scheda:
sed "s/$(echo '\t')//"
echo '\t'produrrà 2 caratteri separati. Il modo portatile POSIX è usare printf '\t'. Questo è il motivo per cui dico: non cercare di rendere portabile il tuo codice non usando bash. È più difficile di quanto pensi. L'utilizzo bashè la cosa più portatile che la maggior parte di noi può fare.
Non è necessario utilizzare sedper eseguire una sostituzione quando in realtà, si desidera semplicemente inserire una tabulazione davanti alla riga. La sostituzione per questo caso è un'operazione costosa rispetto alla semplice stampa, soprattutto quando si lavora con file di grandi dimensioni. È anche più facile da leggere perché non è regex.
es. usando awk
awk '{print "\t"$0}' $filename > temp && mv temp $filename
L'ho usato su Mac:
sed -i '' $'$i\\\n\\\thello\n' filename
sednon supporta \t, né altre sequenze di escape come \nper quella materia. L'unico modo che ho trovato per farlo è stato inserire effettivamente il carattere di tabulazione nello script usando sed.
Detto questo, potresti prendere in considerazione l'utilizzo di Perl o Python. Ecco un breve script Python che ho scritto che uso per tutte le espressioni regolari di flusso:
#!/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:])
Invece di BSD sed, io uso perl:
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
hi
Credo che altri hanno chiarito questo adeguatamente per altri approcci ( sed, AWK, ecc). Tuttavia, bashseguono le mie risposte specifiche (testate su macOS High Sierra e CentOS 6/7).
1) Se OP volesse utilizzare un metodo di ricerca e sostituzione simile a quello originariamente proposto, allora suggerirei di utilizzare perlper questo, come segue. Note: i backslash prima delle parentesi per la regex non dovrebbero essere necessari, e questa riga di codice riflette come $1è meglio usarla che \1con l' perloperatore di sostituzione (ad esempio per la documentazione di Perl 5 ).
perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) Tuttavia, come sottolineato da ghostdog74 , poiché l'operazione desiderata è in realtà quella di aggiungere semplicemente una scheda all'inizio di ogni riga prima di cambiare il file tmp nel file di input / target ( $filename), lo consiglierei di perlnuovo ma con la seguente modifica (S):
perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
3) Ovviamente, il file tmp è superfluo , quindi è meglio fare tutto "a posto" (aggiungendo una -ibandiera) e semplificare le cose a una riga più elegante con
perl -i -pe $'s/^/\t/' $filename