Dalam skrip konfigurasi shell, bagaimana saya bisa menjelaskan perbedaan antara coreutils pada BSD dibandingkan dengan GNU?


9

Hingga bulan ini, konfigurasi shell saya cukup sederhana (hanya dengan .bashrcatau .bash_profilesebagian alias), tetapi saya telah refactoring sehingga saya bisa mendapatkan perilaku yang berbeda tergantung pada apakah saya menggunakan zsh, dan bash. Mereka pertama-tama sumber file konfigurasi shell generik yang harus bekerja untuk apa pun, kemudian mengkhususkan diri untuk shell tertentu yang digunakan (saya simet ke ini)

Saya terkejut hari ini ketika lsberhenti bekerja. Ternyata selama refactoring .bashrc, ada alias

alias ls='ls --color=always'

itu melanggar hal-hal untuk lsdi bash di Terminal di OSX. Setelah saya melihat BSD lssuka -Gwarna, tetapi GNU (atau apa pun yang ada di Ubuntu) suka --color, jelas bahwa beberapa opsi berbeda.

Pertanyaan saya adalah, apa cara terbaik untuk menjelaskan perbedaan pilihan dan antara BSD dan GNU coreutils? Haruskah saya menguji variabel env dalam ifblok untuk melihat OS apa yang digunakan dan menerapkan perilaku yang benar? Atau apakah lebih masuk akal untuk membuat file konfigurasi terpisah untuk setiap OS?

Sementara jawaban untuk pertanyaan-pertanyaan ini mungkin subyektif, sepertinya ikhtisar dari lingkup perbedaan antara BSD dan GNU coreutils dan strategi untuk mengatasi ini untuk membuat konfigurasi generik yang dapat digunakan pada sebagian besar * nix akan cukup objektif.


Mengganti shell tidak akan memperbaiki apa pun, dan ls -cberbeda dari ls --color. Edit pertanyaan Anda untuk diperbaiki.
Mikel

Jawaban:


9

Satu-satunya cara yang dapat diandalkan untuk menulis skrip yang mendukung sistem operasi yang berbeda adalah dengan hanya menggunakan fitur yang ditentukan oleh POSIX.

Untuk hal-hal seperti konfigurasi shell pribadi Anda, Anda dapat menggunakan peretasan yang sesuai dengan kasus penggunaan spesifik Anda. Sesuatu seperti yang berikut ini jelek, tetapi akan mencapai tujuannya.

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi

Saya telah bermain-main dengan metode yang berbeda, dan saya pikir solusi "jelek" Anda cukup bagus dan bahkan tidak jelek. Ternyata, saya tidak memperhatikan ketidakcocokan dalam opsi untuk ls sebelumnya karena saya menggunakan GNU coreutils dari Ports. Ini adalah contoh mengapa melakukan 'jika' pada $ OSTYPE dapat gagal memberikan hasil yang diinginkan.
labirin

Apakah ada cara untuk menekan kesalahan yang berasal dari "jika ls --versi" ketika GNU coreutils tidak ada (tetapi masih dapat menguji coreutils)?
labirin

Oh, jangan pernah berpikir tentang menekan kesalahan. Saya baru saja mengarahkan stderr ke / dev / null sebelum pemipaan untuk grep dan berfungsi seperti yang saya inginkan.
labirin

3
Daripada mencari coreutilssecara eksplisit, mengapa tidak hanya menguji apakah flag warna berfungsi, misalnya if ls --color=auto -d / >/dev/null 2>&1; then ....
Mikel

@mikel jika Anda hanya peduli tentang warna (seperti pada contoh), tidak apa-apa. Jika Anda peduli dengan fitur lain juga, memeriksa coreutils berguna.
jordanm

3

Mengotori kode dengan ifpernyataan untuk melakukan pergantian pada tipe coreutils tidak berfungsi, namun solusi pemrograman bersih untuk menangani berbagai jenis adalah dengan menggunakan polimorfisme . Karena ini Bash, kami tidak memiliki polimorfisme sendiri, tetapi saya telah mengacaukan cara untuk memalsukannya. Satu-satunya persyaratan adalah bahwa .bashrcfile Anda dll. Diatur dalam fungsi.

Pertama saya membuat tes untuk jenis platform coreutils :

get_coreutils_platform() {
    local ls_version="$(ls --version 2>/dev/null)"
    if [[ "$ls_version" == *"GNU coreutils"* ]]; then
        echo gnu
    else
        echo bsd
    fi
}

Kemudian kita dapat mengirim berdasarkan tipe:

platform=$(get_coreutils_platform)
define_standard_aliases_$platform
configure_shell_vars_$platform

Inilah implementasi BSD :

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Perhatikan bahwa kami menggunakan CLICOLORvariabel untuk mengaktifkan warna alih-alih menggunakan alias, yang tampaknya lebih bersih sedikit)

Dan implementasi GNU :

define_standard_aliases_gnu() {
    define_standard_aliases
    alias ls='ls --color=auto'
}

configure_shell_vars_gnu() {
    configure_shell_vars
}

Demi kelengkapan, berikut adalah contoh implementasi dari "basis abstrak":

define_standard_aliases() {
    alias ll='ls -l'
    alias l.='ls -d .*'
}

configure_shell_vars() {
    export EDITOR=vim
}

Ini jauh lebih bersih, kecuali Anda berada di 0,1% dari sistem dengan misalnya GNU ls tetapi tidak diinstal GNU cat (mungkin itu benar-benar tua dan mereka memiliki fileutils tetapi tidak textutils). Saya akan tergoda untuk menggunakannya lsdi operator Anda daripada cat, terutama karena tidak ada alias Anda yang terlibat cat.
Mikel

Selain itu, Anda tidak perlu --color=automenggunakan alias kedua dan ketiga Anda, karena alias pertama menambahkan opsi itu ls.
Mikel

1
@Ikel whoa, saya benar-benar tidak menyadari bahwa aliasitu bersifat rekursif. Itu membuat saya membuat contoh lebih sederhana.
Michael Kropat

Jauh lebih baik. :-)
Mikel

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.