Saya telah menyalin perintah cd C:\foo\bar\
dari PowerShell ke Cygwin dan masih berharap untuk mengeksekusi. Saya sekarang mencoba menjalankan substitusi untuk mengganti semua \
dengan /
:
$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed
Tidak yakin mengapa saya mendapatkan substitusi gagal.
Saya juga mencoba:
$ !!:gs/\\/q
Hanya untuk melihat apakah penggantian itu masalahnya. Ini bukan. Sekarang saya penasaran!
Mengapa saya mendapatkan "substitusi gagal"?
cd 'C:\foo\bar'
!!:gs/\\/\/
fc -s '\'='/' -1
bekerja di bawah bash default Ubuntu LTS. Beri tahu saya jika berfungsi di bawah Cygwin juga. Saya mengirim lebih banyak kata dalam jawabannya.!!:gs/\\/\//
. @Asturfc -s '\'='/' -1
mendapat perilaku yang diharapkan. ini mungkin bug di bash.Jawaban:
garis miring juga merupakan pembatas dari perintah pengganti Anda, jadi Anda harus menghindarinya sebagai string pengganti agar tidak mengakhiri substitusi lebih awal
atau lebih tepatnya seperti yang disarankan dalam komentar, dengan menggunakan sesuatu selain garis miring sebagai pembatas
Tapi ini sepertinya hanya bekerja di
tcsh
(shell yang biasanya ditugaskan di mana saya berada), saya tidak bisa mendapatkan perintah untuk bekerjabash
karena tampaknya melarikan diri tidak bekerja pada argumen pertama dari:s
sumber
!!:gs|\\|/
mungkin sedikit lebih mudah dibaca.:s
do't tampaknya menjadi regex nyataJawaban singkat: builtin
fc
(perintah fix) dari bashfc
adalah perintah, built-in di shell bash, dibuat untuk mengedit & mengeksekusi kembali perintah sejarah.Ia hadir di CygWin juga dan berfungsi pada semua distribusi Linux yang saya uji:
Beberapa penjelasan
fc
adalah bash built-in perintah untuk daftar atau mengedit dan re-menjalankan perintah dari daftar sejarah.-1
akan mengambil perintah terakhir dalam sejarah. Perhatikan bahwa genap!!
didefinisikan (dibaca dariman bash
) sebagai-s
untuk mengganti pola dengan yang lain. Kali ini darihelp fc
(perintah bawaan begituhelp
):Oke maksud mereka
pat=rep
alih-alihOLD=NEW
...'\'
dan'/'
.Beberapa kata lebih lanjut tentang mengapa Anda mendapatkan "substitusi gagal"
Tampaknya untuk
s
modifikator belum (belum) menerapkan substitusi karakter backslash\
, itulah yang melarikan diri. Untuk memastikan kita harus melihat kode, misalnya, versi gnu dari ekspansi sejarah bash (tetapi ada perintah di atas untuk mendapatkan apa yang Anda coba lakukan ... jadi saya menganggapnya malas ....).Beberapa catatan:
Kami beranggapan bahwa itu akan berfungsi setiap RegEx kami temukan bekerja dengan
sed
, tetapi tidak dijamin. Garis miring terbalik adalah karakter pelarian dari ekspansi dan masalahnya ada di sini. Selain itu perilaku ekspansi terkait denganshopt
opsi, jadi kita harus mulai melihat kasus per kasus ...Ketika Anda menempelkan string
cd C:\Foo\Bar
dalam bash shell Anda, itu akan diperluas dan akan muncul untuk penerjemah sebagaicd C:FooBar
; dalam bentuk ini akan disimpan dalam$_
variabel internal juga.Jika Anda malah menempelkan
cd "C:\Foo\Bar"
ataucd 'C:\Foo\Bar'
dalam$_
variabel Anda harus menemukanC:\Foo\Bar
.Karena ekspansi History dilakukan segera setelah baris lengkap dibaca, sebelum shell memecahnya menjadi kata-kata, Anda mungkin tergoda untuk mulai menggunakannya dengan sedikit bashism , misalnya, dengan beberapa turunan dari (mungkin menambah
:p
atau:q
,""
, parsing dan sebagainya ...)Ini adalah momen untuk mengingat bahwa tidak aman untuk mulai bermain dengan path dan nama file , terutama jika itu berasal dari clipboard windows (baca secara umum halaman Mengapa tidak parse
ls
?, Pada dasarnya terkait dengan kemungkinan untuk menggunakan tab, spasi dan baris baru sebagai karakter yang benar untuk nama file dan direktori ...).Terlebih lagi ketika Anda menempelkan teks yang diambil dengan mouse , Anda juga dapat menempelkan ruang utama. Ini dapat menghindari bahwa perintah Anda akan selesai dalam sejarah (itu tergantung dari opsi shell ...). Jika demikian, pengikut Anda
!!
akan menjadi perintah yang tidak terkontrol ... (lihat contoh dalam jawaban lain ).Ini adalah risiko nyata yang tidak dibutuhkan .Kesimpulan
Jika tidak mudah saya mulai berpikir kita melakukan sesuatu yang salah
;-)
Ad mual: percobaan kecil
Saya telah mengaktifkan
histverify
di shell maka ...kemudian saya tekan Enterdan sebagai ekspansi terverifikasi saya temukan
lalu saya tekan Enterlagi dan bergema
Ini tampaknya menunjukkan bahwa yang
substitution failed
dihasilkan dalam ekspansi sejarah diproses sebelum ekspansi Brace , jadi pertama-tama , dan tampaknya mengkonfirmasi bahwas
pengubah sejarah belum (belum) memproses substitusi\
karakter sebagai regex nyata. ..sumber
Anda dapat menggunakan
sed
untuk mengganti dan menjalankan hasilnya.Ada beberapa varian yang mungkin untuk perintah seperti itu, tetapi pada bash saya hanya yang ini berfungsi:
Yang
\\
ditambahkan ke!!
adalah dalam kasus perintah terakhir diakhiri dengan garis miring terbalik. Tanpa itu, shell akan bingung dan meminta kelanjutan dari garis.Anda juga bisa menambahkan ini sebagai fungsi bash dalam file
~/.bashrc
:Berikut ini cara kerjanya di Bash saya di Windows:
Untuk menjelaskan bagaimana
A=
perintah memberikan nilai yang tepat ke variabel shellA
:tail
mengambil dua baris terakhir dari sejarah perintah, yang memberikan gariscd \mnt\c
diikuti denganslash
sendirinya. Bagian darihistory | tail -n 2
juga dapat ditulis sebagaihistory 2
.head
ambil baris pertama yaitucd \mnt\c
cut
memotong nomor baris yang disediakan olehhistory
sed
mengganti semua anti-garis miring dengan garis miringeval
mengeksekusi isi dari variabelA
sumber
A=$(echo "!!\\" | sed 's,\\,/,g');eval $A
tidak berfungsi ketika perintah diakhiri dengan backslash. Anda dipaksa untuk menambahkan spasi, mis. Ke yangC:\Foo\Bar\
lain, seperti yang Anda katakan, shell akan menunggu kelanjutan garis. Anda juga dapat menekan enter dua kali. Dalam kasus pertama Anda mendapatkanC:/Foo/Bar /
(dengan spasi sebelum/
; dalam detik itu akan menghasilkan kesalahan. Fungsi berfungsi dengan baik.Saya tidak berpikir Anda bisa melakukan ini. Anda perlu menyalin / menempel lagi.
Masalahnya tidak terkait dengan slash beeing juga pemisah perintah pengganti, karena perintah pengganti menerima pemisah apa pun. Masalahnya adalah tentang garis miring yang harus diganti, yang telah diperlakukan sebagai pelarian karakter yang tidak berguna di sebelah kanan mereka.
Oleh karena itu, ketika Anda memanggil perintah pengganti, backslash sudah hilang dari sumbernya. Coba panggil ulang perintah apa adanya (
!!
). Alih-alih mencetak perintah yang sama persis termasukc:\foo
, itu akan mengeksekusi perintah minus backslash yang sudah diproses yang menghasilkanc:foo
.Dan jelas Anda tidak dapat menemukan atau mengganti karakter yang hilang. Mencoba melakukannya akan memunculkan kesalahan.
sumber
echo c:\Foo
diikuti oleh!!:gs,F,\\f,
. Tapi Mengganti pelarian backslash itu sendiri tampaknya menjadi sakit.