ทดแทนแบ็กสแลชสำหรับฟอร์เวิร์ดสแลชในคำสั่งสุดท้าย


10

ฉันได้คัดลอกคำสั่งcd C:\foo\bar\จาก PowerShell ไปยัง Cygwin และคาดหวังอย่างเต็มที่ว่ามันจะทำงาน ตอนนี้ฉันพยายามเรียกใช้การทดแทนเพื่อแทนที่ทั้งหมด\ด้วย/:

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

ไม่แน่ใจว่าทำไมฉันถึงได้รับการทดแทนล้มเหลว

ฉันก็ลอง:

$ !!:gs/\\/q

เพียงเพื่อดูว่าแทนที่เป็นปัญหา มันไม่ใช่. ตอนนี้ฉันอยากรู้อยากเห็น!

ทำไมฉันถึงได้รับ "การทดแทนล้มเหลว"?


2
ฉันไม่มี cygwin อยู่ในมือในขณะนี้ แต่ฉันคิดว่าเส้นทางของ Windows กำลังทำงานอยู่ ... คุณเคยลองอ้างเหตุผลไหม? เช่นcd 'C:\foo\bar'
mpy

@mpy มันใช้งานได้จริงด้วย! ไม่ทราบว่าฉันไม่ได้ติดอยู่กับการทดแทน
แทนเนอร์ฟอล์กเนอร์

1
"จะเปิดให้คำตอบโดยใช้ zsh เช่นกัน". ต้นฉบับของคุณ!!:gs/\\/\/ใช้งานได้ใน zsh ...
Kamil Maciorowski

@TannerFaulkner fc -s '\'='/' -1ทำงานภายใต้การทุบตีเริ่มต้นของ Ubuntu LTS แจ้งให้เราทราบหากการทำงานภายใต้ Cygwin ด้วย ฉันโพสต์คำเพิ่มเติมในคำตอบ
Hastur

1
!!:gs/\\/\//ฉันคิดว่าพฤติกรรมทุบตีทั่วไปที่นี่เป็นที่ทับขวามีการประมวลผลเป็นหนีก่อนที่จะทดแทนที่เกิดขึ้นใน @Hastur fc -s '\'='/' -1ได้รับพฤติกรรมที่คาดหวัง นี่อาจเป็นข้อผิดพลาดในการทุบตี
quixotic

คำตอบ:


6

เครื่องหมายทับหน้ายังเป็นตัวคั่นของคำสั่งทดแทนของคุณดังนั้นคุณต้องหนีมันเป็นสตริงแทนที่เพื่อไม่ให้จบการแทนที่ก่อน

!!:gs/\\/\//

หรือมากกว่าอย่างชัดเจนตามที่แนะนำในความคิดเห็นโดยใช้บางสิ่งบางอย่างนอกเหนือจากเครื่องหมายทับเป็นตัวคั่น

!!:gs|\\|/|

แต่สิ่งนี้ดูเหมือนว่าจะทำงานในtcsh(เชลล์ที่ได้รับมอบหมายโดยทั่วไปว่าฉันอยู่ที่ไหน) ฉันไม่สามารถรับคำสั่งให้ทำงานได้bashเนื่องจากดูเหมือนว่าการหลบหนีจะไม่ทำงานในอาร์กิวเมนต์แรกของ:s


ไม่มีความสุข :( ข้อผิดพลาดเดียวกันi.imgur.com/QFQR0xF.png
Tanner Faulkner

1
แค่หมายเหตุ: !!:gs|\\|/อาจจะอ่านง่ายขึ้นนิดหน่อย
mpy

1
ฉันไม่สามารถรับมันได้ในการทุบตี หาเรื่องแรกของ:sdoen't ดูเหมือนจะเป็น regex จริง
infixed

4

คำตอบสั้น ๆ : builtin fc(คำสั่งแก้ไข)ของ bash

fcเป็นคำสั่งในตัวในเชลล์ bash ทำเพื่อแก้ไขและเรียกใช้คำสั่งของประวัติอีกครั้ง
มีอยู่ใน CygWin ด้วยและทำงานบนดิสทริบิวชัน Linux ทั้งหมดที่ฉันทดสอบ:

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

คำอธิบายบางอย่าง

  • fcเป็นคำสั่งในตัวของ bash เพื่อแสดงรายการหรือแก้ไขและเรียกใช้คำสั่งอีกครั้งจากรายการประวัติ
  • -1จะใช้คำสั่งสุดท้ายในประวัติศาสตร์ โปรดทราบว่าแม้!!จะถูกกำหนด (อ่านจากman bash) เป็น

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

  • -sเพื่อแทนที่รูปแบบด้วยอีก เวลานี้จากhelp fc(คำสั่งในตัวดังนั้นhelp):

    ด้วยรูปแบบ `fc -s [pat = rep ... ] [command] 'คำสั่งจะถูกเรียกใช้งานอีกครั้งหลังจากการแทนที่ OLD = NEW ถูกดำเนินการ

    ตกลงพวกเขาหมายถึงpat=repแทนที่จะOLD=NEW...

  • รูปแบบจะถูกอ่านโดยเปลือกดังนั้นเราจึงต้องปกป้องพวกเขาโดยอ้างข้อความ: และ'\''/'

บางคำเพิ่มเติมเกี่ยวกับสาเหตุที่คุณได้รับ "การแทนที่ล้มเหลว"

มันดูเหมือนว่าสำหรับs ปรับปรุงไม่ได้ (ยัง) ดำเนินการเปลี่ยนตัวของตัวอักษรทับขวาที่\ที่เป็นหนึ่งหลบหนี เพื่อให้แน่ใจว่าเราควรเห็นรหัสตัวอย่างของการขยายประวัติ bash รุ่น gnu (แต่มีคำสั่งด้านบนเพื่อรับสิ่งที่คุณพยายามทำ ... ดังนั้นฉันจึงขี้เกียจ .... )

หมายเหตุบางส่วน:

  1. เรานำไปสู่การคิดว่ามันจะทำงานได้ดีกับ RegEx แต่ละครั้งsedแต่ก็ไม่รับประกัน แบ็กสแลชเป็นตัวหนีของการขยายตัวและปัญหาอยู่ที่นี่ ยิ่งไปกว่านั้นพฤติกรรมของการขยายตัวนั้นเกี่ยวข้องกับshoptตัวเลือกต่างๆดังนั้นเราควรเริ่มเห็นเป็นกรณี ๆ ไป ...

  2. เมื่อคุณวางสตริงcd C:\Foo\Barในเปลือก bash ของคุณมันจะถูกขยายและมันจะปรากฏขึ้นสำหรับล่ามเป็นcd C:FooBar; ในรูปแบบนี้มันจะถูกเก็บไว้ใน$_ตัวแปรภายในด้วย
    หากคุณวางแทนcd "C:\Foo\Bar"หรือcd 'C:\Foo\Bar'ในตัวแปรคุณควรจะหา$_ เนื่องจากการขยายตัวของประวัติศาสตร์จะดำเนินการทันทีหลังจากที่สายสมบูรณ์จะอ่านก่อนที่จะแบ่งเปลือกมันเป็นคำพูดที่คุณอาจจะอยากจะเริ่มต้นที่จะใช้กับบางbashismมากหรือน้อยธรรมดาเช่นมีรากศัพท์มาจาก (อาจจะเพิ่มหรือ, วจีวิภาคและอื่น ๆ ... ) C:\Foo\Bar
    :p:q""

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

    นี่เป็นช่วงเวลาที่ต้องจำไว้ว่ามันไม่ปลอดภัยที่จะเริ่มเล่นกับเส้นทางและชื่อไฟล์โดยเฉพาะอย่างยิ่งถ้าพวกเขามาจากคลิปบอร์ดของ windows (อ่านโดยทั่วไปในหน้าทำไมไม่แยกวิเคราะห์ls?มันเกี่ยวข้องกับความเป็นไปได้ที่จะใช้แท็บ ช่องว่างและการขึ้นบรรทัดใหม่เป็นอักขระที่ถูกต้องสำหรับชื่อไฟล์และรายการไดเรกทอรี ... )
    ยิ่งกว่านั้นเมื่อคุณวางข้อความที่จับด้วยเมาส์คุณอาจวางพื้นที่นำหน้าด้วย สิ่งนี้อาจหลีกเลี่ยงว่าคำสั่งของคุณจะเสร็จสิ้นในประวัติศาสตร์ (ขึ้นอยู่กับตัวเลือกของเชลล์ ... ) ถ้าอย่างนั้นการติดตามของคุณ!!จะเป็นคำสั่งที่ไม่ได้ควบคุม ... (ดูตัวอย่างในคำตอบอื่น )นี่เป็นความเสี่ยงที่จับต้องไม่ได้

ข้อสรุป

การขยายประวัติแนะนำคำจากรายการประวัติลงในอินพุตสตรีมทำให้ง่ายต่อการทำซ้ำคำสั่งแทรกอาร์กิวเมนต์ไปยังคำสั่งก่อนหน้าในบรรทัดอินพุตปัจจุบันหรือแก้ไขข้อผิดพลาดในคำสั่งก่อนหน้าอย่างรวดเร็ว

ถ้าไม่ใช่เรื่องง่ายฉันเริ่มคิดว่าเรากำลังทำอะไรผิดพลาด ;-)


อาการคลื่นไส้: เป็นการทดลองเล็กน้อย

ฉันเปิดใช้งานhistverifyในเชลล์แล้ว ...

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

จากนั้นฉันกดEnterและตรวจสอบการขยายตัวที่ฉันพบ

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

จากนั้นฉันกดEnterอีกครั้งและมันก็ก้อง

D:FooBar 1A 2A

นี่ดูเหมือนว่าจะบ่งบอกว่าสิ่งที่substitution failedสร้างขึ้นในการขยายประวัติประมวลผลก่อนการขยาย Brace ก่อนอื่นเลยและดูเหมือนว่าจะยืนยันว่าโมดิsฟายเออร์ประวัตินั้นยังไม่ได้ประมวลผลการแทนที่\ตัวละครในฐานะ regex จริง ..


2

คุณสามารถใช้sedเพื่อทดแทนและดำเนินการผลลัพธ์

มีหลายรูปแบบที่เป็นไปได้สำหรับคำสั่งดังกล่าว แต่ในทุบตีของฉันเท่านั้นที่ทำงาน:

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

\\จะถูกเพิ่มลง!!ในกรณีคำสั่งสุดท้ายสิ้นสุดลงด้วยเครื่องหมาย หากไม่มีมันเชลล์จะสับสนและถามถึงความต่อเนื่องของบรรทัด

คุณสามารถเพิ่มสิ่งนี้เป็นฟังก์ชั่นทุบตีในไฟล์~/.bashrc:

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

นี่คือวิธีการทำงานบน Bash ของฉันบน Windows:

ทุบตี

เพื่ออธิบายวิธีที่A=คำสั่งกำหนดค่าที่ถูกต้องให้กับตัวแปรเชลล์A:

  • tailใช้สองบรรทัดสุดท้ายจากประวัติคำสั่งซึ่งให้บรรทัดของการcd \mnt\cติดตามด้วยslashตัวเอง ส่วนหนึ่งของนอกจากนี้ยังอาจจะเขียนเป็นhistory | tail -n 2history 2
  • head ใช้บรรทัดแรกซึ่งก็คือ cd \mnt\c
  • cut ตัดหมายเลขบรรทัดที่จัดหาโดย history
  • sed แทนที่ anti-slashes ทั้งหมดด้วยเครื่องหมายทับ
  • eval รันเนื้อหาของตัวแปร A

สวัสดีแฮรี่ ขออภัยที่จะกล่าวว่าใน GNU bash รุ่น 4.3.11 (1) ของฉันA=$(echo "!!\\" | sed 's,\\,/,g');eval $Aไม่ทำงานเมื่อคำสั่งสิ้นสุดด้วยแบ็กสแลช คุณถูกบังคับให้เพิ่มช่องว่างเช่นที่C:\Foo\Bar\ อื่น ๆ อย่างที่คุณพูดเชลล์จะรอให้มีการต่อเนื่องของบรรทัด คุณยังสามารถกด Enter สองครั้ง ในกรณีแรกที่คุณได้รับC:/Foo/Bar /(โดยมีช่องว่างก่อนหน้า/; ในกรณีที่สองจะสร้างข้อผิดพลาดฟังก์ชันทำงานได้ดี
Hastur

ฉันเขียนฟังก์ชั่นเพราะ (1) ใช้งานง่ายกว่ามากและ (2) หนึ่งซับดูเหมือนจะขึ้นอยู่กับการนำไปใช้
harrymc

-1

ฉันไม่คิดว่าคุณสามารถทำได้ คุณต้องคัดลอก / ผ่านมาอีกครั้ง

ปัญหาไม่เกี่ยวข้องกับ slash beeing และตัวคั่นคำสั่ง replace เนื่องจากคำสั่ง replace ยอมรับตัวคั่นใด ๆ ปัญหาเป็นเรื่องเกี่ยวกับแบ็กสแลชที่จะถูกแทนที่ซึ่งได้รับการปฏิบัติแล้วว่าเป็นการหลบหนีของตัวละครที่ไร้ประโยชน์ทางด้านขวา

ดังนั้นเมื่อคุณเรียกใช้คำสั่งทดแทนแบ็กสแลชจะหายไปจากแหล่งที่มา เพียงลองเรียกคำสั่งใหม่ตามที่เป็นอยู่ ( !!) แทนการพิมพ์คำสั่งเดียวกันแน่นอนรวมถึงมันจะรันคำสั่งลบทับขวาแล้วประมวลผลซึ่งส่งผลให้เกิดc:\fooc:foo

และแน่นอนคุณไม่สามารถค้นหาหรือแทนที่ตัวละครที่ขาดหายไป การพยายามทำเช่นนั้นจะทำให้เกิดข้อผิดพลาด


1
ดี. นั่นเป็นสิ่งที่ผิดที่สุดตั้งแต่การทดสอบนี้ใช้งานได้จริง: ตามมาด้วยecho c:\Foo !!:gs,F,\\f,แต่การทดแทนแบ็กสแลชหนีนั้นดูเหมือนจะเป็นความเจ็บปวด
A. Loiseau
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.