Gema karakter tab dalam skrip bash

313

Bagaimana cara menggema satu atau lebih karakter tab menggunakan skrip bash? Ketika saya menjalankan kode ini

res='       'x # res = "\t\tx"
echo '['$res']' # expect [\t\tx]

Saya mengerti

res=[ x] # that is [<space>x]
kalyanji
sumber

Jawaban:

529
echo -e ' \t '

akan menampilkan 'spasi ruang baris baru' ( -eberarti 'aktifkan interpretasi backslash lolos'):

$ echo -e ' \t ' | hexdump -C
00000000  20 09 20 0a                                       | . .|
Johannes Weiss
sumber
Terimakasih Johannes. Anda membantu saya menemukan solusi ini: res = '\ t \ t'x; echo -e '[' $ res ']'
kalyanji
2
Apakah Anda kebetulan tahu, mengapa echo -etidak berhasil dari Makefiles?
dma_k
23
Itu karena echo -ebukan POSIX dan makepanggilan /bin/shyang biasanya bukan penggunaan program gunakan secara interaktif, dan biasanya belum -ediimplementasikan. Untuk portabilitas, gunakan printf '\t'saja.
Jo So
Di Darwin (macOS), manhalaman untuk echoperintah tidak menyebutkan opsi -e. Namun, opsi ini diterima.
ePi272314
75

Gunakan printf, bukan echo.

Ada beberapa versi echoperintah yang berbeda. Ada /bin/echo(yang mungkin atau mungkin bukan versi GNU Coreutils, tergantung pada sistem), dan echoperintah dibangun ke sebagian besar shell. Versi yang berbeda memiliki cara yang berbeda (atau tidak ada cara) untuk menentukan atau menonaktifkan lolos untuk karakter kontrol.

printf, di sisi lain, memiliki variasi yang jauh lebih sedikit. Itu bisa ada sebagai perintah, biasanya /bin/printf, dan itu dibangun ke dalam beberapa shell (bash dan zsh memilikinya, tcsh dan ksh tidak), tetapi berbagai versi jauh lebih mirip satu sama lain daripada versi yang berbeda echo. Dan Anda tidak harus mengingat opsi baris perintah (dengan beberapa pengecualian; GNU Coreutils printf menerima --versiondan --help, dan built-in bash printf menerima -v varuntuk menyimpan output dalam variabel).

Sebagai contoh Anda:

res='           'x # res = "\t\tx"
printf '%s\n' "[$res]"

Dan sekarang saatnya bagi saya untuk mengakui bahwa itu echoakan berhasil juga untuk contoh yang Anda tanyakan; Anda hanya perlu memberikan tanda kutip ganda di sekitar argumen:

echo "[$res]"

seperti kmkaplan menulis (dua setengah tahun yang lalu, saya baru saja memperhatikan!). Masalah dengan perintah asli Anda:

res='           'x # res = "\t\tx"
echo '['$res']' # expect [\t\tx]

tidak dengan echo; itu adalah shell mengganti tab dengan spasi sebelum echopernah melihatnya.

echobaik untuk output sederhana, seperti echo hello world, tetapi Anda harus menggunakannya printfkapan pun Anda ingin melakukan sesuatu yang lebih kompleks. Anda bisa mulai echobekerja, tetapi kode yang dihasilkan cenderung gagal ketika Anda menjalankannya dengan echoimplementasi yang berbeda atau shell yang berbeda.

Keith Thompson
sumber
1
Saya suka yang ini, itu memungkinkan saya untuk menggunakan pengetahuan printf dan semua penentu format.
Arun
@JezenThomas: Tidak lebih dipilih karena menjawab pertanyaan dengan cara lain daripada yang diminta. Pertanyaannya secara khusus menyebutkan gema, dan gema bukan kata kerja tetapi perintah.
Paulo Neves
@PauloNeves: Saya akan mengatakan itu digunakan sebagai kata kerja dalam pertanyaan: "Bagaimana saya menggemakan satu atau lebih karakter tab menggunakan skrip bash?"
Keith Thompson
34

Letakkan string Anda di antara tanda kutip ganda :

echo "[$res]"
kmkaplan
sumber
1
sama di sini - ini yang saya coba dulu. -e bekerja dengan baik
froderik
2
@kmkaplan Bekerja untuk saya di zsh - gagal untuk saya di bash
Kal
34

Anda juga dapat mencoba:

echo Hello$'\t'world.
jbatista
sumber
4
+1 untuk solusi yang lebih umum. Saya telah menggunakan bash selama bertahun-tahun dan saya baru belajar ini sekarang!
Aryeh Leib Taurog
Ini jauh lebih umum daripada jawaban yang diterima karena dapat digunakan tanpa gema.
jwan
22

Anda perlu menggunakan flag -e untuk echo maka Anda bisa

echo -e "\t\t x"
Belajar
sumber
16

Dari halaman bash man:

Kata-kata dalam bentuk $ 'string' diperlakukan secara khusus. Kata diperluas ke string, dengan karakter backslash-escaped diganti sebagaimana ditentukan oleh standar ANSI C.

Jadi Anda bisa melakukan ini:

echo $'hello\tworld'
esoriano
sumber
Mengapa ini bekerja pada cli tetapi tidak dalam skrip bash?
Freek
13

Gunakan kata demi kata keystroke, ^V( CTRL+V, C-v, apa pun ).

Saat Anda mengetik ^Vdi terminal (atau di sebagian besar editor Unix), karakter berikut akan diambil kata demi kata . Anda bisa menggunakan ini untuk mengetikkan karakter tab literal di dalam string yang Anda gema.

Sesuatu seperti karya berikut:

echo "^V<tab>"     # CTRL+V, TAB

Bash docs ( qv , "quotes-insert")

dikutip-masukkan (Cq, Cv) Tambahkan karakter berikutnya yang Anda ketik ke baris kata demi kata. Ini adalah cara memasukkan urutan kunci seperti Cq, misalnya.

catatan: menurut ini, ALT+TAB harus melakukan hal yang sama, tetapi kita semua terikat urutan itu untuk beralih jendela sehingga kita tidak dapat menggunakannya

tab-insert (M-TAB) Masukkan karakter tab.

-

Catatan: Anda dapat menggunakan strategi ini dengan semua jenis karakter yang tidak biasa. Seperti pengembalian kereta:

echo "^V^M"        # CTRL+V, CTRL+M

Ini karena carriage return adalah ASCII 13, dan M adalah huruf ke-13 dari alfabet, jadi ketika Anda mengetik ^M, Anda mendapatkan karakter ASCII ke-13. Anda dapat melihatnya beraksi menggunakan ls^M, pada prompt kosong, yang akan memasukkan carriage return, menyebabkan prompt untuk bertindak seperti Anda menekan return. Ketika karakter-karakter ini biasanya ditafsirkan, kata demi kata membuat Anda mendapatkan karakter literal.

kaya remer
sumber
1
Seandainya saya bisa memberi Anda lebih banyak upvotes untuk ini. Saya tidak ingin menggunakan -e dalam argumen saya dalam kasus ini, dan ini bekerja dengan baik. Terima kasih!
Aaron R.
"... sebagian besar editor Unix"? Mencoba memasukkan ini dengan vi dan emacs dan itu tidak memberikan hasil yang diinginkan baik.
GreenMatt
Itu keren sekali! Dan menyelamatkan hari saya ketika mencoba menggunakan grepuntuk menangkap garis yang berisi tabkarakter.
Joël
11

Menggunakan gema untuk mencetak nilai variabel adalah perangkap Bash yang umum. Tautan referensi:

http://mywiki.wooledge.org/BashPitfalls#echo_.24foo

Anonim
sumber
Keren, saya suka "BashPitfalls", sepotong materi yang hebat dan meringankan banyak rasa sakit dari pekerjaan sehari-hari saya!
Jerry Tian
+1 karena ini benar benar. Tetapi perhatikan bahwa string kalyanji dimulai dengan "[" dan tidak mengandung "\".
kmkaplan
2

Jika Anda ingin menggunakan echo "a\tb"skrip, Anda menjalankan skrip sebagai:

# sh -e myscript.sh

Atau, Anda dapat memberikan kepada myscript.sh izin eksekusi, dan kemudian jalankan script.

# chmod +x myscript.sh
# ./myscript.sh
ATC
sumber
0
res="\t\tx"
echo -e "[${res}]"
yanghaogn
sumber