GNU/Linux >> Belajar Linux >  >> Linux

Mengapa Printf Lebih Baik Dari Echo?

Saya telah mendengar bahwa printf lebih baik dari echo . Saya hanya dapat mengingat satu contoh dari pengalaman saya di mana saya harus menggunakan printf karena echo tidak berfungsi untuk memasukkan beberapa teks ke dalam beberapa program di RHEL 5.8 tetapi printf telah melakukan. Tapi ternyata, ada perbedaan lain, dan saya ingin menanyakan apa perbedaannya serta apakah ada kasus tertentu saat menggunakan satu vs yang lain.

Jawaban yang Diterima:

Pada dasarnya, ini adalah masalah portabilitas (dan keandalan).

Awalnya, echo tidak menerima opsi apa pun dan tidak memperluas apa pun. Yang dilakukannya hanyalah mengeluarkan argumennya yang dipisahkan oleh karakter spasi dan diakhiri oleh karakter baris baru.

Sekarang, seseorang berpikir akan lebih baik jika kita bisa melakukan hal-hal seperti echo "nt" untuk menampilkan karakter baris atau tab baru, atau memiliki opsi untuk tidak menampilkan karakter baris baru tambahan.

Mereka kemudian berpikir lebih keras tetapi alih-alih menambahkan fungsionalitas itu ke shell (seperti perl di mana di dalam tanda kutip ganda, t sebenarnya berarti karakter tab), mereka menambahkannya ke echo .

David Korn menyadari kesalahan tersebut dan memperkenalkan bentuk baru dari kutipan shell:$'...' yang kemudian disalin oleh bash dan zsh tapi saat itu sudah sangat terlambat.

Sekarang ketika echo UNIX standar menerima argumen yang berisi dua karakter dan t , alih-alih mengeluarkannya, itu menghasilkan karakter tab. Dan segera setelah ia melihat c dalam sebuah argumen, ia berhenti mengeluarkan (jadi baris baru yang tertinggal juga tidak keluar).

Shell/vendor/versi Unix lainnya memilih untuk melakukannya secara berbeda:mereka menambahkan -e opsi untuk memperluas urutan pelarian, dan -n opsi untuk tidak menampilkan baris baru yang tertinggal. Beberapa memiliki -E untuk menonaktifkan urutan pelarian, beberapa memiliki -n tapi bukan -e , daftar urutan pelarian yang didukung oleh satu echo implementasi belum tentu sama dengan yang didukung oleh yang lain.

Sven Mascheck memiliki halaman bagus yang menunjukkan sejauh mana masalahnya.

Pada echo itu implementasi yang mendukung opsi, umumnya tidak ada dukungan -- untuk menandai akhir opsi (echo bawaan dari beberapa shell non-Bourne, dan zsh mendukung - untuk itu), jadi misalnya, sulit untuk menampilkan "-n" dengan echo dalam banyak cangkang.

Pada beberapa shell seperti bash atau ksh93 ² atau yash ($ECHO_STYLE variabel), perilaku bahkan tergantung pada bagaimana shell dikompilasi atau lingkungan (GNU echo perilaku juga akan berubah jika $POSIXLY_CORRECT ada di lingkungan dan dengan versi, zsh dengan bsd_echo-nya opsi, beberapa berbasis pdksh dengan posix their opsi atau apakah mereka disebut sebagai sh atau tidak). Jadi dua bash echo s, bahkan dari versi bash yang sama tidak dijamin akan berperilaku sama.

POSIX mengatakan:jika argumen pertama adalah -n atau argumen apa pun berisi garis miring terbalik, maka perilakunya tidak ditentukan . bash echo dalam hal itu bukan POSIX dalam hal itu misalnya echo -e tidak mengeluarkan -e<newline> seperti yang dibutuhkan POSIX. Spesifikasi UNIX lebih ketat, melarang -n dan membutuhkan perluasan beberapa urutan pelarian termasuk c satu untuk berhenti mengeluarkan.

Spesifikasi tersebut tidak benar-benar datang untuk menyelamatkan di sini karena banyak implementasi yang tidak sesuai. Bahkan beberapa bersertifikat sistem seperti macOS tidak sesuai.

Untuk benar-benar mewakili kenyataan saat ini, POSIX harus benar-benar mengatakan:jika argumen pertama cocok dengan ^-([eEn]*|-help|-version)$ diperpanjang regexp atau argumen apa pun berisi garis miring terbalik (atau karakter yang pengkodeannya berisi pengkodean karakter garis miring terbalik seperti α di lokal menggunakan charset BIG5), maka perilakunya tidak ditentukan.

Secara keseluruhan, Anda tidak tahu apa echo "$var" akan ditampilkan kecuali Anda dapat memastikan bahwa $var tidak mengandung karakter garis miring terbalik dan tidak dimulai dengan - . Spesifikasi POSIX sebenarnya memberitahu kita untuk menggunakan printf sebagai gantinya.

Jadi maksudnya tidak bisa menggunakan echo untuk menampilkan data yang tidak terkontrol. Dengan kata lain, jika Anda sedang menulis skrip dan mengambil input eksternal (dari pengguna sebagai argumen, atau nama file dari sistem file...), Anda tidak dapat menggunakan echo untuk menampilkannya.

Tidak apa-apa:

echo >&2 Invalid file.

Ini bukan:

echo >&2 "Invalid file: $file"

(Meskipun itu akan berfungsi dengan baik dengan beberapa (tidak sesuai dengan UNIX) echo implementasi seperti bash saat xpg_echo opsi belum diaktifkan dengan satu atau lain cara seperti pada waktu kompilasi atau melalui lingkungan).

Terkait:Memproses setiap baris output dari `ping` segera dalam pipeline?

file=$(echo "$var" | tr ' ' _) tidak OK di sebagian besar implementasi (pengecualian adalah yash dengan ECHO_STYLE=raw (dengan peringatan bahwa yash Variabel 's tidak dapat menampung urutan byte yang sewenang-wenang, jadi bukan nama file yang sewenang-wenang) dan zsh 's echo -E - "$var" ).

printf , di sisi lain lebih dapat diandalkan, setidaknya jika terbatas pada penggunaan dasar echo .

printf '%sn' "$var"

Akan menampilkan konten $var diikuti oleh karakter baris baru terlepas dari karakter apa yang mungkin ada di dalamnya.

printf '%s' "$var"

Akan menampilkannya tanpa karakter baris baru tambahan.

Sekarang, ada juga perbedaan antara printf implementasi. Ada inti fitur yang ditentukan oleh POSIX, tetapi kemudian ada banyak ekstensi. Misalnya, beberapa mendukung %q mengutip argumen tetapi cara melakukannya bervariasi dari satu shell ke shell lainnya, beberapa mendukung uxxxx untuk karakter unicode. Perilaku bervariasi untuk printf '%10sn' "$var" di lokal multi-byte, setidaknya ada tiga hasil berbeda untuk printf %b '123'

Tetapi pada akhirnya, jika Anda tetap menggunakan set fitur POSIX dari printf dan jangan mencoba melakukan sesuatu yang terlalu mewah dengannya, Anda keluar dari masalah.

Tapi ingat argumen pertama adalah formatnya, jadi tidak boleh berisi data variabel/tidak terkontrol.

echo yang lebih andal dapat diimplementasikan menggunakan printf , seperti:

echo() ( # subshell for local scope for $IFS
  IFS=" " # needed for "$*"
  printf '%sn' "$*"
)

echo_n() (
  IFS=" "
  printf %s "$*"
)

echo_e() (
  IFS=" "
  printf '%bn' "$*"
)

Subkulit (yang menyiratkan pemijahan proses tambahan di sebagian besar implementasi shell) dapat dihindari menggunakan local IFS dengan banyak cangkang, atau dengan menuliskannya seperti:

echo() {
  if [ "$#" -gt 0 ]; then
     printf %s "$1"
     shift
     if [ "$#" -gt 0 ]; then
       printf ' %s' "[email protected]"
     fi
  fi
  printf 'n'
}

Catatan

1. bagaimana bash echo perilaku dapat diubah.

Dengan bash , pada saat dijalankan, ada dua hal yang mengontrol perilaku echo (di samping enable -n echo atau mendefinisikan ulang echo sebagai fungsi atau alias):
xpg_echo bash opsi dan apakah bash dalam mode posix. posix mode dapat diaktifkan jika bash disebut sebagai sh atau jika POSIXLY_CORRECT ada di lingkungan atau dengan posix pilihan:

Perilaku default pada sebagian besar sistem:

$ bash -c 'echo -n "
Linux
  1. Mengapa Menggunakan Instal Daripada Cp Dan Mkdir?

  2. Apa yang Membuat Cloud Hosting Lebih Baik Dari VPS Tradisional?

  3. Lzma Vs Bzip2 – Kompresi Lebih Baik daripada bzip2 di UNIX / Linux

  1. Bagaimana cara menulis karakter non-ASCII menggunakan gema?

  2. Bagaimana menangani lebih dari 10 parameter di shell

  3. Mengapa sudo:perintah bundel tidak ditemukan?

  1. [Linux]:Mendiagnosis Masalah Jaringan menggunakan MTR – lebih baik daripada traceroute!

  2. Apakah (Ubuntu) algoritma penyalinan file Linux lebih baik daripada Windows 7?

  3. Mengapa router perangkat keras bekerja lebih baik daripada router Linux dengan spesifikasi yang lebih baik (RAM &CPU)?