GNU/Linux >> Belajar Linux >  >> Linux

Mengutip Di Ssh $host $foo Dan Ssh $host Jenis Konstruksi "Sudo Su User -c $foo"?

Saya sering akhirnya mengeluarkan perintah kompleks melalui ssh; perintah ini melibatkan pemipaan ke awk atau perl satu baris, dan sebagai hasilnya berisi tanda kutip tunggal dan $. Saya tidak dapat menemukan aturan yang keras dan cepat untuk melakukan kutipan dengan benar, atau menemukan referensi yang baik untuk itu. Misalnya, pertimbangkan hal berikut:

# what I'd run locally:
CMD='pgrep -fl java | grep -i datanode | awk '{print $1}'
# this works with ssh $host "$CMD":
CMD='pgrep -fl java | grep -i datanode | awk '"'"'{print $1}'"'"

(Perhatikan tanda kutip tambahan dalam pernyataan awk.)

Tetapi bagaimana saya membuatnya berfungsi, mis. ssh $host "sudo su user -c '$CMD'" ? Apakah ada resep umum untuk mengelola kutipan dalam skenario seperti itu?..

Jawaban yang Diterima:

Berurusan dengan beberapa level kutipan (sungguh, beberapa level parsing/interpretasi) bisa menjadi rumit. Ini membantu untuk mengingat beberapa hal:

  • Setiap “tingkat kutipan” berpotensi melibatkan bahasa yang berbeda.
  • Aturan mengutip berbeda-beda menurut bahasa.
  • Saat menangani lebih dari satu atau dua level bersarang, biasanya paling mudah untuk bekerja "dari bawah, atas" (yaitu terdalam ke terluar).

Tingkat Mengutip

Mari kita lihat contoh perintah Anda.

pgrep -fl java | grep -i datanode | awk '{print $1}'

Contoh perintah pertama Anda (di atas) menggunakan empat bahasa:shell Anda, regex di pgrep , ekspresi reguler di grep (yang mungkin berbeda dari bahasa regex di pgrep ), dan awk . Ada dua tingkat interpretasi yang terlibat:shell dan satu tingkat setelah shell untuk masing-masing perintah yang terlibat. Hanya ada satu tingkat kutipan yang eksplisit (kutipan shell ke awk ).

ssh host …

Selanjutnya Anda menambahkan level ssh di atas. Ini secara efektif merupakan level shell lain:ssh tidak menafsirkan perintah itu sendiri, ia menyerahkannya ke shell di ujung jarak jauh (melalui (mis.) sh -c … ) dan shell itu menginterpretasikan string tersebut.

ssh host "sudo su user -c …"

Kemudian Anda bertanya tentang menambahkan level shell lain di tengah dengan menggunakan su (melalui sudo , yang tidak menginterpretasikan argumen perintahnya, jadi kita bisa mengabaikannya). Pada titik ini, Anda memiliki tiga tingkat penyarangan yang sedang berlangsung (awk → cangkang, cangkang → cangkang (ssh ), shell → shell (su user -c ), jadi saya menyarankan menggunakan pendekatan "bawah, atas". Saya akan berasumsi bahwa shell Anda kompatibel dengan Bourne (mis. sh , abu , tanda hubung , ksh , bash , zsh , dll.). Beberapa jenis cangkang lainnya (ikan , rc , dll.) mungkin memerlukan sintaks yang berbeda, tetapi metode ini tetap berlaku.

Bawah, Atas

  1. Rumuskan string yang ingin Anda wakili di tingkat terdalam.
  2. Pilih mekanisme kutipan dari repertoar kutipan bahasa tertinggi berikutnya.
  3. Kutip string yang diinginkan sesuai dengan mekanisme kutipan yang Anda pilih.
    • Sering ada banyak variasi cara menerapkan mekanisme kutipan yang mana. Melakukannya dengan tangan biasanya merupakan masalah latihan dan pengalaman. Saat melakukannya secara terprogram, biasanya yang terbaik adalah memilih yang paling mudah untuk dilakukan dengan benar (biasanya yang “paling literal” (paling sedikit lolos)).
  4. Secara opsional, gunakan string kutipan yang dihasilkan dengan kode tambahan.
  5. Jika Anda belum mencapai tingkat kutipan/interpretasi yang diinginkan, ambil string kutipan yang dihasilkan (ditambah kode tambahan apa pun) dan gunakan sebagai string awal pada langkah 2.

Mengutip Variasi Semantik

Hal yang perlu diingat di sini adalah bahwa setiap bahasa (tingkat kutipan) dapat memberikan semantik yang sedikit berbeda (atau bahkan semantik yang sangat berbeda) untuk karakter kutipan yang sama.

Sebagian besar bahasa memiliki mekanisme kutipan "harfiah", tetapi mereka berbeda dalam hal literalnya. Kutipan tunggal dari cangkang mirip Bourne sebenarnya literal (yang berarti Anda tidak dapat menggunakannya untuk mengutip satu karakter kutipan itu sendiri). Bahasa lain (Perl, Ruby) kurang literal karena mereka menafsirkan beberapa urutan garis miring terbalik di dalam wilayah yang dikutip tunggal secara non-harfiah (khususnya, \ dan ' menghasilkan dan ' , tetapi urutan garis miring terbalik lainnya sebenarnya literal).

Terkait:Php:bcompiler_write_exe_footer — Menulis pos awal, dan menandatangani hingga akhir file jenis exe

Anda harus membaca dokumentasi untuk setiap bahasa Anda untuk memahami aturan kutipannya dan sintaks keseluruhannya.

Contoh Anda

Tingkat terdalam dari contoh Anda adalah awk program.

{print $1}

Anda akan menyematkan ini di baris perintah shell:

pgrep -fl java | grep -i datanode | awk …

Kita perlu melindungi (minimal) ruang dan $ di awk program. Pilihan yang jelas adalah menggunakan tanda kutip tunggal di shell di sekitar keseluruhan program.

  • '{print $1}'

Ada pilihan lain:

  • {print $1} langsung keluar dari ruang dan $
  • {print' $'1} kutipan tunggal hanya spasi dan $
  • "{print $1}" kutip ganda keseluruhan dan lepas $
  • {print" $"1} kutip ganda hanya spasi dan $
    Ini mungkin sedikit membengkokkan aturan (tidak lolos $ di akhir string yang dikutip ganda adalah literal), tetapi tampaknya berfungsi di sebagian besar shell.

Jika program menggunakan koma di antara kurung kurawal buka dan tutup, kita juga perlu mengutip atau menghindari koma atau kurung kurawal untuk menghindari "ekspansi kurung kurawal" di beberapa shell.

Kami memilih '{print $1}' dan sematkan di sisa "kode" shell:

pgrep -fl java | grep -i datanode | awk '{print $1}'

Selanjutnya, Anda ingin menjalankan ini melalui su dan sudo .

sudo su user -c …

su user -c … seperti some-shell -c … (kecuali berjalan di bawah beberapa UID lain), jadi su hanya menambahkan tingkat shell lain. sudo tidak menafsirkan argumennya, sehingga tidak menambahkan level kutipan apa pun.

Kami membutuhkan level shell lain untuk string perintah kami. Kita bisa memilih petik tunggal lagi, tapi kita harus memberikan penanganan khusus pada petik tunggal yang ada. Cara yang biasa terlihat seperti ini:

'pgrep -fl java | grep -i datanode | awk '''{print $1}''

Ada empat string di sini yang akan ditafsirkan dan digabungkan oleh shell:string kutipan tunggal pertama (pgrep … awk ), kutipan tunggal yang lolos, awk . yang dikutip tunggal program, satu kutipan lolos lainnya.

Tentu saja ada banyak alternatif:

  • pgrep -fl java | grep -i datanode | awk '{print $1} lepas dari semua yang penting
  • pgrep -fl java|grep -i datanode|awk '{print$1} sama, tetapi tanpa spasi yang berlebihan (bahkan dalam awk program!)
  • "pgrep -fl java | grep -i datanode | awk '{print $1}'" kutip ganda semuanya, lepas $
  • 'pgrep -fl java | grep -i datanode | awk '"'"'{print $1}'"'" variasi Anda; sedikit lebih lama dari cara biasanya karena menggunakan tanda kutip ganda (dua karakter) daripada escape (satu karakter)

Menggunakan kutipan yang berbeda di tingkat pertama memungkinkan variasi lain di tingkat ini:

  • 'pgrep -fl java | grep -i datanode | awk "{print $1}"'
  • 'pgrep -fl java | grep -i datanode | awk {print $1}'

Menyematkan variasi pertama di sudo /*su* baris perintah berikan ini:

sudo su user -c 'pgrep -fl java | grep -i datanode | awk '''{print $1}''

Anda dapat menggunakan string yang sama dalam konteks level shell tunggal lainnya (mis. ssh host … ).

Selanjutnya, Anda menambahkan level ssh di atas. Ini secara efektif merupakan level shell lain:ssh tidak menafsirkan perintah itu sendiri, tetapi menyerahkannya ke shell di ujung jarak jauh (melalui (mis.) sh -c … ) dan shell itu menginterpretasikan string tersebut.

ssh host …

Prosesnya sama:ambil string, pilih metode kutipan, gunakan, sematkan.

Menggunakan tanda kutip tunggal lagi:

'sudo su user -c '''pgrep -fl java | grep -i datanode | awk ''\'''{print $1}''\'

Sekarang ada sebelas string yang ditafsirkan dan digabungkan:'sudo su user -c ' , lolos dari tanda kutip tunggal, 'pgrep … awk ' , tanda kutip tunggal lolos, garis miring terbalik lolos, dua tanda kutip tunggal lolos, tanda kutip tunggal awk program, tanda kutip tunggal yang lolos, garis miring terbalik yang lolos, dan tanda kutip tunggal yang lolos terakhir.

Terkait:Kotak GNOME Boot Dari ISO Setelah Menginstal Sistem Operasi?

Bentuk akhir terlihat seperti ini:

ssh host 'sudo su user -c '''pgrep -fl java | grep -i datanode | awk ''\'''{print $1}''\'

Ini agak sulit untuk diketik dengan tangan, tetapi sifat literal dari kutipan tunggal shell memudahkan untuk mengotomatisasi sedikit variasi:

#!/bin/sh

sq() { # single quote for Bourne shell evaluation
    # Change ' to ''' and wrap in single quotes.
    # If original starts/ends with a single quote, creates useless
    # (but harmless) '' at beginning/end of result.
    printf '%sn' "$*" | sed -e "s/'/'\\''/g" -e 1s/^/'/ -e $s/$/'/
}

# Some shells (ksh, bash, zsh) can do something similar with %q, but
# the result may not be compatible with other shells (ksh uses $'...',
# but dash does not recognize it).
#
# sq() { printf %q "$*"; }

ap='{print $1}'
s1="pgrep -fl java | grep -i datanode | awk $(sq "$ap")"
s2="sudo su user -c $(sq "$s1")"

ssh host "$(sq "$s2")"

Linux
  1. Cara Membatasi Akses SSH untuk Pengguna dengan LShell (Limited Shell)

  2. Ssh – Bagaimana Cara Menyangkal Proses yang Berjalan Dan Mengaitkannya ke Shell Layar Baru?

  3. Dasar-dasar pengguna dan basis data MySQL

  1. CentOS / RHEL :Cara Menonaktifkan / Mengaktifkan login ssh pengguna root dan non-root langsung

  2. Apa perbedaan antara /bin/false dan /sbin/nologin sebagai shell pengguna nologin?

  3. Bisakah saya menonaktifkan login terakhir SSH dan MOTD berdasarkan per pengguna?

  1. Ssh – Membatasi Pengguna Ssh/scp/sftp ke Direktori?

  2. Ssh Dan Izin Direktori Rumah?

  3. shell berbeda untuk pengguna root dan non-root