Dấu gạch chéo ngược thay thế cho dấu gạch chéo trong lệnh cuối cùng


10

Tôi đã sao chép lệnh cd C:\foo\bar\từ PowerShell sang Cygwin và hoàn toàn mong đợi nó sẽ thực thi. Bây giờ tôi đang cố gắng thay thế tất cả \bằng /:

$ !!:gs/\\/\/
bash: :gs/\\/\/: substitution failed

Không chắc chắn tại sao tôi nhận được sự thay thế thất bại.

Tôi cũng đã thử:

$ !!:gs/\\/q

Chỉ để xem nếu thay thế là vấn đề. Nó không thể. Bây giờ tôi tò mò!

Tại sao tôi nhận được "sự thay thế thất bại"?


2
Tôi không có Cygwin trong tay ngay bây giờ, nhưng tôi nghĩ, các đường dẫn Windows đang hoạt động ... bạn đã thử trích dẫn lập luận chưa? Tức làcd 'C:\foo\bar'
mpy

@mpy Điều này thực sự hoạt động quá! Không biết tôi đã không bị mắc kẹt với sự thay thế.
Tanner Faulkner

1
"Sẽ được mở cho một câu trả lời bằng cách sử dụng zsh là tốt". Bản gốc của bạn !!:gs/\\/\/không hoạt động trong
zshay

@TannerFaulkner fc -s '\'='/' -1hoạt động theo bash mặc định của Ubuntu LTS. Hãy cho tôi biết nếu nó hoạt động theo Cygwin quá. Tôi đăng nhiều từ hơn trong câu trả lời.
Hastur

1
Tôi nghĩ rằng hành vi bash chung ở đây là dấu gạch chéo ngược được xử lý như thoát trước khi sự thay thế xảy ra !!:gs/\\/\//. @Hastur fc -s '\'='/' -1sẽ có hành vi mong đợi. đây có thể là một lỗi trong bash.
quixotic

Câu trả lời:


6

một dấu gạch chéo về phía trước cũng là dấu phân cách của lệnh thay thế của bạn, vì vậy bạn phải thoát nó dưới dạng chuỗi thay thế để không kết thúc sớm sự thay thế

!!:gs/\\/\//

hoặc rõ ràng hơn như được đề xuất trong các bình luận, bằng cách sử dụng một cái gì đó ngoài dấu gạch chéo làm dấu phân cách

!!:gs|\\|/|

Nhưng điều này dường như chỉ hoạt động trong tcsh(vỏ thường được gán ở nơi tôi đang ở), tôi không thể nhận lệnh để làm việc bashvì dường như thoát không hoạt động trên đối số đầu tiên của:s


Không có niềm vui :( Lỗi tương tự i.imgur.com/QFQR0xF.png
Tanner Faulkner

1
Chỉ cần một nhận xét: !!:gs|\\|/có thể dễ đọc hơn một chút.
mpy

1
Tôi không thể làm cho nó hoạt động trong bash. Cuộc tranh luận đầu tiên :sdường như không phải là một cuộc biểu tình thực sự
thúc vào

4

Câu trả lời ngắn: lệnh dựng sẵn fc(lệnh fix) của bash

fclà lệnh, được tích hợp trong bash shell, được thực hiện để chỉnh sửa & thực hiện lại các lệnh của lịch sử.
Nó cũng có mặt trên CygWin và nó hoạt động trên tất cả các bản phân phối Linux mà tôi đã thử nghiệm:

fc  -s '\'='/' -1

Một số giải thích

  • fclà bash built-in lệnh vào danh sách hoặc chỉnh sửa và tái thực hiện các lệnh từ danh sách lịch sử.
  • -1sẽ nhận lệnh cuối cùng trong lịch sử. Lưu ý rằng thậm chí !!được định nghĩa (đọc từ man bash) là

    !! Refer to the previous command. This is a synonym for! -1 '.

  • -sđể thay thế một mô hình bằng một mô hình khác. Lần này từ help fc(lệnh tích hợp như vậy help):

    Với định dạng `fc -s [pat = rep ...] [lệnh] ', LỰA CHỌN được thực thi lại sau khi thay thế OLD = NEW được thực hiện.

    Ok họ có nghĩa là pat=repthay vì OLD=NEW...

  • Các mẫu sẽ được đọc bởi trình bao vì vậy chúng ta phải bảo vệ chúng bằng dấu ngoặc kép: '\''/'.

Một số từ thêm về lý do tại sao bạn nhận được "thay thế thất bại"

Có vẻ như đối với công cụ s sửa đổi chưa (chưa) thực hiện thay thế ký tự dấu gạch chéo ngược \, đó là lối thoát. Để chắc chắn, chúng ta sẽ thấy mã, ví dụ, phiên bản gnu của bản mở rộng lịch sử bash (nhưng có lệnh trên để có được những gì bạn đang cố gắng làm ... vì vậy tôi lười biếng ....).

Một số lưu ý:

  1. Chúng tôi có thể nghĩ rằng nó sẽ hoạt động với mỗi RegEx mà chúng tôi thấy đang hoạt động sed, nhưng nó không được bảo đảm. Dấu gạch chéo ngược là ký tự thoát của bản mở rộng và vấn đề nằm ở đây. Ngoài ra, hành vi của việc mở rộng có liên quan đến các shopttùy chọn, vì vậy chúng ta nên bắt đầu xem từng trường hợp ...

  2. Khi bạn dán chuỗi cd C:\Foo\Barvào bash shell, nó sẽ được mở rộng và nó sẽ xuất hiện cho trình thông dịch như cd C:FooBar; ở dạng này, nó cũng sẽ được lưu trong $_biến nội bộ.
    Nếu bạn thay vì dán cd "C:\Foo\Bar"hoặc cd 'C:\Foo\Bar'trong $_ biến bạn nên tìm C:\Foo\Bar.
    Vì việc mở rộng Lịch sử được thực hiện ngay lập tức sau khi đọc một dòng hoàn chỉnh, trước khi trình bao phá vỡ nó thành từ, bạn có thể bị bắt đầu sử dụng nó với một số bashism ít nhiều, ví dụ, với một số dẫn xuất từ ​​(có thể thêm :phoặc :q, "", phân tích cú pháp và vân vân ...)

    !!:0 ${_//\\/\/}

    Đây là thời điểm cần nhớ rằng không an toàn khi bắt đầu chơi với đường dẫn và tên tệp , đặc biệt nếu chúng đến từ bảng tạm của windows (đọc chung trang Tại sao không phân tích ls?, Về cơ bản liên quan đến khả năng sử dụng tab, dấu cách và dòng mới dưới dạng ký tự chính xác cho tên tệp và thư mục ...).
    Ngoài ra, khi bạn dán một văn bản được chụp bằng chuột , bạn cũng có thể dán một không gian hàng đầu. Điều này có thể tránh việc lệnh của bạn sẽ kết thúc trong lịch sử (nó phụ thuộc vào các tùy chọn shell ...). Nếu vậy, sau đây của bạn !!sẽ là một lệnh không được kiểm soát ... (xem một ví dụ trong câu trả lời khác ).Đây là một rủi ro hữu hình không cần thiết .

Phần kết luận

Mở rộng lịch sử giới thiệu các từ từ danh sách lịch sử vào luồng đầu vào, giúp dễ dàng lặp lại các lệnh, chèn các đối số vào một lệnh trước đó vào dòng đầu vào hiện tại hoặc sửa lỗi nhanh chóng trong các lệnh trước đó.

Nếu nó không dễ dàng tôi bắt đầu nghĩ rằng chúng ta đang làm gì đó sai ;-)


Quảng cáo nauseam: một thử nghiệm nhỏ

Tôi đã kích hoạt histverifytrong trình bao rồi ...

shopt -s histverify
echo C:\Foo\Bar
!!:s|C|D| {1,2}A

sau đó tôi nhấn Entervà khi xác minh mở rộng tôi tìm thấy

echo D:\Foo\Bar {1,2}A

sau đó tôi nhấn Entermột lần nữa và nó lặp lại

D:FooBar 1A 2A

Điều này dường như chỉ ra rằng cái substitution failedđược tạo ra trong bản mở rộng lịch sử được xử lý trước khi mở rộng Brace , vì vậy trước hết , và dường như nó xác nhận rằng bộ ssửa đổi lịch sử đã không (chưa) xử lý việc thay thế \nhân vật như một regex thực sự. ..


2

Bạn có thể sử dụng sedđể thay thế và thực hiện kết quả.

Có một số biến thể có thể cho một lệnh như vậy, nhưng trên bash của tôi chỉ có một biến thể này hoạt động:

A=$(echo "!!\\" | sed 's,\\,/,g');eval $A

Các \\sẽ được thêm vào !!là trong trường hợp lệnh cuối cùng chấm dứt với một dấu gạch chéo. Không có nó, vỏ sẽ bị lẫn lộn và yêu cầu tiếp tục dòng.

Bạn cũng có thể thêm hàm này dưới dạng hàm bash trong tệp ~/.bashrc:

function slash {
   A=$(history | tail -n 2 | head -n 1 | cut -c 8- | sed 's,\\,/,g')
   eval $A
}

Đây là cách nó hoạt động trên Bash của tôi trên Windows:

bash

Để giải thích cách A=lệnh gán giá trị đúng cho biến shell A:

  • taillấy hai dòng cuối cùng từ lịch sử lệnh, nó đưa ra các dòng cd \mnt\ctheo sau slashnó. Một phần history | tail -n 2cũng có thể được viết là history 2.
  • head lấy dòng đầu tiên cd \mnt\c
  • cut cắt bỏ số dòng được cung cấp bởi history
  • sed thay thế tất cả các dấu gạch chéo bằng dấu gạch chéo
  • eval thực hiện các nội dung của biến A

Chào Harry. Rất tiếc phải nói rằng trên phiên bản GNU bash 4.3.11 (1) của A=$(echo "!!\\" | sed 's,\\,/,g');eval $Atôi không hoạt động khi lệnh kết thúc bằng dấu gạch chéo ngược. Bạn buộc phải thêm một khoảng trắng, ví dụ như C:\Foo\Bar\ khác, như bạn đã nói, shell sẽ chờ tiếp tục dòng. Bạn cũng có thể nhấn enter hai lần. Trong trường hợp đầu tiên bạn nhận được C:/Foo/Bar /(với một khoảng trắng trước /; trong lần thứ hai, nó sẽ phát sinh lỗi. Hàm này hoạt động tốt.
Hastur

Tôi đã viết hàm vì (1) Nó dễ sử dụng hơn nhiều và (2) Lớp lót dường như quá phụ thuộc vào việc thực hiện.
harrymc

-1

Tôi không nghĩ bạn có thể làm điều này. Bạn cần sao chép / quá khứ một lần nữa.

Vấn đề không liên quan đến dấu gạch chéo cũng là dấu phân cách lệnh thay thế, vì lệnh thay thế chấp nhận bất kỳ dấu phân cách nào. Vấn đề là về các dấu gạch chéo ngược được thay thế, đã được coi là lối thoát đơn giản vô dụng của nhân vật bên phải họ.

Do đó, khi bạn gọi lệnh thay thế, dấu gạch chéo ngược đã biến mất khỏi nguồn. Chỉ cần cố gắng gọi lại lệnh như là ( !!). Thay vì in chính xác cùng một lệnh bao gồm c:\foo, nó sẽ thực thi lệnh trừ các dấu gạch chéo ngược đã được xử lý dẫn đến c:foo.

Và rõ ràng bạn không thể tìm thấy hay thay thế một nhân vật bị mất tích. Cố gắng làm như vậy sẽ gây ra lỗi.


1
Tốt. Điều đó cuối cùng là sai vì thử nghiệm này thực sự hoạt động: echo c:\Footiếp theo !!:gs,F,\\f,. Nhưng việc thay thế dấu gạch chéo ngược tự nó dường như là một nỗi đau.
A. Loiseau
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.