Tidak dapat menggunakan! $ Dalam skrip?

11

Hanya ingin tahu mengapa ini tidak berhasil

#!/bin/bash 

ls /bin
ls !$

Saya berharap untuk menjalankan ls /bindua kali, tetapi yang kedua menimbulkan kesalahan karena !$tidak ditafsirkan

Apakah saya melewatkan sesuatu, atau !$hanya bekerja di baris perintah?

Saya tidak dapat menemukan bagian yang relevan di man bash(di mac)

bunga aster
sumber
9
Meskipun ada solusi, apakah ini benar-benar cara terbaik untuk mencapai ini dalam naskah? riwayat dinonaktifkan secara default karena suatu alasan ketika Anda menjalankan non-interaktif - skrip panjang akan meng-spam file .bash_history. Tidak mengatakan itu tidak layak untuk menanyakan hal ini, tetapi hanya jika Anda berpikir untuk menggunakan ini dalam skrip, apakah ini benar-benar cara terbaik?
flungo

Jawaban:

26

Riwayat dan perluasan riwayat dinonaktifkan secara default saat shell dijalankan secara non-interaktif.

Anda membutuhkan:

#!/bin/bash 

set -o history
set -o histexpand

ls /bin
ls !$

atau:

SHELLOPTS=history:histexpand bash script.sh

itu akan memengaruhi semua instance bash yang script.shmungkin berjalan.

cuonglm
sumber
9
Hati-hati dengan SHELLOPTS, itu akan mempengaruhi yang bashberjalan script.sh, tetapi juga semua bashcontoh lain yang script.shmungkin akhirnya berjalan (seperti bashskrip lain ...).
Stéphane Chazelas
Dan itu tidak akan memengaruhi instance lain bash yang menjalankan skrip Anda.
Blacklight Shining
Saya pikir jawaban ini akan membaik jika komentar @ StéphaneChazelas diedit ke dalamnya.
Oliphaunt - mengembalikan Monica
7

Hal yang waras untuk dilakukan adalah

ls /bin
ls $_

atau

set ls /bin
$*
$*

atau

c='ls /bin'
$c
$c

Peringatan: perlu diingat bahwa masing-masing dilengkapi dengan beberapa jebakan. Solusi $ _ hanya menangkap argumen tunggal terakhir: sehingga ls foo barakan meninggalkan $ _ berisi adil bar. Yang menggunakan setakan menimpa argumen ( $1, $2, dll). Dan semua ini sebagai tulisan akan bekerja, tetapi ketika digeneralisasikan ke perintah yang lebih kompleks (di mana melarikan diri dan spasi putih), Anda bisa mengalami beberapa kesulitan. Misalnya: ls 'foo bar'(di mana argumen pathname tunggal foo barberisi dua atau lebih spasi, atau karakter spasi putih lainnya) tidak akan berperilaku benar dalam salah satu dari contoh ini. Pelarian yang benar (mungkin digabungkan dengan evalperintah), atau menggunakan "$@"alih-alih $*, mungkin diperlukan untuk mengatasi kasus-kasus itu.

Steven Penny
sumber
1
Memberi +1 untuk jawaban yang portabel dan tidak menyalahgunakan bashism yang dimaksudkan untuk mempermudah penggunaan interaktif. (Sebagai tambahan, keinginan bash untuk secara interaktif memperluas tanda seru di pengaturan default adalah sesuatu yang saya temukan berlawanan dengan pengguna shell lain, dan kontraproduktif karena selalu mengacaukan saya ketika saya mencoba melakukan perintah shell yang rumit).
mtraceur
Meskipun seperti yang ditulis pada saat ini, saya ragu-ragu untuk memberikan +1 karena masalah yang mungkin dimiliki oleh skrip shell pemula ketika mencoba menggeneralisasikannya ke perintah yang lebih kompleks. Saya menyarankan edit untuk setidaknya menambahkan paragraf peringatan yang menjelaskan kemungkinan jebakannya.
mtraceur
@traceur: ini tidak portabel, hanya bekerja di bash, zsh, ksh (jika dua perintah tidak berada di baris yang sama). Bekerja di dasbor, mksh hanya ketika interaktif
cuonglm
@cuongim: Maaf, saya mungkin terlalu sembrono. The $_cara adalah tidak portabel, Anda benar. The setPendekatan bekerja di dasbor non-interaktif, dan dengan ${1+"$@"}(ditambah zsh alias global) trik harus umum, meskipun saya samar-samar ingat bahwa setmemiliki sejarah tidak menjadi sempurna portabel dengan beberapa (lama?) Kerang. Pendekatan define-a-variable-holding-the-command-and-then-eval-it, terutama menggunakan pelolosan yang tepat dan evalperintah yang sebenarnya , benar-benar umumnya portabel sejauh yang saya tahu.
mtraceur