sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Saya mengharapkan sedskrip ini untuk menyisipkan tabdi depan setiap baris $filenametetapi sebenarnya tidak. Untuk beberapa alasan itu memasukkan sebagai tgantinya.
sed "s/\(.*\)/\t\1/" $filename > $sedTmpFile && mv $sedTmpFile $filename
Saya mengharapkan sedskrip ini untuk menyisipkan tabdi depan setiap baris $filenametetapi sebenarnya tidak. Untuk beberapa alasan itu memasukkan sebagai tgantinya.
Jawaban:
Tidak semua versi sedmengerti \t. Cukup masukkan tab literal sebagai gantinya (tekan Ctrl- Vlalu Tab).
\tdi bagian pengganti ekspresi (itu dikenali \tdi bagian pencocokan pola dengan baik)
Menggunakan Bash Anda dapat memasukkan karakter TAB secara terprogram seperti ini:
TAB=$'\t'
echo 'line' | sed "s/.*/${TAB}&/g"
echo 'line' | sed 's/.*/'"${TAB}"'&/g' # use of Bash string concatenation
$'string'penjelasan yang kurang. Sebenarnya saya curiga, karena penggunaan yang sangat canggung sehingga Anda mungkin memiliki pemahaman yang tidak lengkap (seperti yang kebanyakan kita lakukan dengan bash). Lihat penjelasan saya di bawah ini: stackoverflow.com/a/43190120/117471
$TABdi dalam tanda kutip tunggal, jadi Anda harus menggunakannya tanda kutip ganda.
*tanda kutip ganda di dalam ... ini akan diperlakukan sebagai bola, bukan sebagai ekspresi reguler yang Anda inginkan.
@sedit berada di jalur yang benar, tetapi agak canggung untuk mendefinisikan variabel.
Cara untuk melakukan ini di bash adalah dengan meletakkan tanda dolar di depan string kutipan tunggal Anda.
$ 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
Jika string Anda perlu menyertakan ekspansi variabel, Anda dapat menggabungkan string yang dikutip seperti ini:
$ timestamp=$(date +%s)
$ echo -e '1\n2\n3' | sed "s/.*/$timestamp"$'\t&/g'
1491237958 1
1491237958 2
1491237958 3
Dalam bash $'string'menyebabkan "ekspansi ANSI-C". Dan itulah yang sebagian besar dari kita harapkan ketika kita menggunakan hal-hal seperti \t, \r, \n, dll Dari: https://www.gnu.org/software/bash/manual/html_node/ANSI_002dC-Quoting.html#ANSI_002dC-Quoting
Kata-kata dalam bentuk $ 'string' diperlakukan secara khusus. Kata tersebut diperluas menjadi string , dengan karakter pelolosan garis miring terbalik diganti seperti yang ditentukan oleh standar ANSI C. Urutan escape dengan garis miring terbalik, jika ada, didekodekan ...
Hasil yang diperluas adalah kutipan tunggal, seolah-olah tanda dolar tidak ada.
Menurut saya pribadi, sebagian besar upaya untuk menghindari bash itu konyol karena menghindari bashisme TIDAK * membuat kode Anda portabel. (Kode Anda akan kurang rapuh jika Anda shebang ke bash -eudaripada jika Anda mencoba menghindari bash dan penggunaan sh[kecuali Anda adalah ninja POSIX mutlak].) Tetapi daripada memiliki argumen religius tentang itu, saya hanya akan memberikan yang TERBAIK * jawaban.
$ echo -e '1\n2\n3' | sed "s/.*/$(printf '\t')&/g"
1
2
3
* Jawaban Terbaik? Ya, karena salah satu contoh kesalahan kebanyakan skrip shell anti-bash dalam kodenya adalah penggunaan echo '\t'seperti dalam jawaban @ robrecord . Itu akan bekerja untuk GNU echo, tapi tidak BSD echo. Itu dijelaskan oleh The Open Group di http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html#tag_20_37_16 Dan ini adalah contoh mengapa mencoba menghindari bashism biasanya gagal.
Saya telah menggunakan sesuatu seperti ini dengan shell Bash di Ubuntu 12.04 (LTS):
Untuk menambahkan baris baru dengan tab, kedua saat pertama cocok:
sed -i '/first/a \\t second' filename
Untuk mengganti pertama dengan tab, kedua :
sed -i 's/first/\\t second/g' filename
\\tdan tidak \t.
Gunakan $(echo '\t'). Anda membutuhkan tanda kutip di sekitar pola.
Misalnya. Untuk menghapus tab:
sed "s/$(echo '\t')//"
echo '\t'akan mengeluarkan 2 karakter terpisah. Cara portabel POSIX adalah dengan menggunakan printf '\t'. Inilah sebabnya saya katakan: Jangan mencoba membuat kode Anda portabel dengan tidak menggunakan bash. Ini lebih sulit dari yang Anda pikirkan. Menggunakan bashadalah hal paling portabel yang dapat dilakukan kebanyakan dari kita.
Anda tidak perlu menggunakan seduntuk melakukan substitusi padahal sebenarnya Anda hanya ingin menyisipkan tab di depan baris. Penggantian untuk kasus ini adalah operasi yang mahal dibandingkan dengan hanya mencetaknya, terutama saat Anda bekerja dengan file besar. Lebih mudah dibaca juga karena bukan regex.
misalnya menggunakan awk
awk '{print "\t"$0}' $filename > temp && mv temp $filename
Saya menggunakan ini di Mac:
sed -i '' $'$i\\\n\\\thello\n' filename
sedtidak mendukung \t, atau urutan pelarian lainnya seperti \ndalam hal ini. Satu-satunya cara yang saya temukan untuk melakukannya adalah dengan benar-benar memasukkan karakter tab dalam skrip menggunakan sed.
Meskipun demikian, Anda mungkin ingin mempertimbangkan untuk menggunakan Perl atau Python. Berikut skrip Python singkat yang saya tulis yang saya gunakan untuk semua ekspresi reguler aliran:
#!/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:])
Alih-alih BSD sed, saya menggunakan perl:
ct@MBA45:~$ python -c "print('\t\t\thi')" |perl -0777pe "s/\t/ /g"
hi
Saya pikir orang lain telah menjelaskan ini cukup untuk pendekatan lain ( sed, AWK, dll). Namun, bashjawaban spesifik saya (diuji pada macOS High Sierra dan CentOS 6/7) mengikuti.
1) Jika OP ingin menggunakan metode cari-dan-ganti yang mirip dengan yang mereka usulkan semula, maka saya akan menyarankan penggunaan perluntuk ini, sebagai berikut. Catatan: garis miring terbalik sebelum tanda kurung untuk regex seharusnya tidak diperlukan, dan baris kode ini mencerminkan cara $1yang lebih baik untuk digunakan daripada \1dengan perloperator substitusi (misalnya per dokumentasi Perl 5 ).
perl -pe 's/(.*)/\t$1/' $filename > $sedTmpFile && mv $sedTmpFile $filename
2) Namun, seperti yang ditunjukkan oleh ghostdog74 , karena operasi yang diinginkan sebenarnya hanya menambahkan tab di awal setiap baris sebelum mengubah file tmp ke file input / target ( $filename), saya akan merekomendasikan perllagi tetapi dengan modifikasi berikut (s):
perl -pe 's/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
## OR
perl -pe $'s/^/\t/' $filename > $sedTmpFile && mv $sedTmpFile $filename
3) Tentu saja, file tmp tidak berguna , jadi lebih baik melakukan semuanya 'di tempat' (menambahkan -itanda) dan menyederhanakan semuanya menjadi satu baris yang lebih elegan dengan
perl -i -pe $'s/^/\t/' $filename