อาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้าคืออะไร


12

$_ ถูกกล่าวว่าเป็นอาร์กิวเมนต์สุดท้ายของคำสั่งก่อนหน้า

ดังนั้นฉันสงสัยว่าทำไมมันไม่ใช่EDITOR="emacs -nw"แต่EDITORในตัวอย่างต่อไปนี้?

ทำไมไม่"emacs -nw"เป็นส่วนหนึ่งของการโต้แย้งครั้งสุดท้าย

โดยทั่วไปแล้วคำจำกัดความของการโต้แย้งคืออะไรและการโต้แย้งครั้งสุดท้ายเป็นอย่างไร

ขอบคุณ

$ export EDITOR="emacs -nw"
$ echo $_
EDITOR

3
ฉันคิดว่ามันเป็นเพราะเหตุผลเดียวกับที่ shellcheck บอกคุณว่าอย่าส่งออกตัวแปรในบรรทัดเดียวกับที่คุณกำหนด การมอบหมายเกิดขึ้นจากนั้นตัวแปรจะถูกส่งออก EDITORเป็นข้อโต้แย้งในการส่งออก
jesse_b

FWIW, pdkshและdashจะรวมถึงค่าที่ได้รับมอบหมาย แต่ksh93จะทำงานเป็นbashไม่
Kusalananda

zsh: ภาพพิมพ์export FOO=bar; echo $_ export
ilkkachu

@Jesse_b สิ่งทั้งหมดเป็นอาร์กิวเมนต์ / ตัวถูกดำเนินการสุดท้าย (รวมถึงค่าที่กำหนด) แต่อาจมีบางสิ่งที่เกี่ยวข้องกับความจริงที่ว่าexportเป็นยูทิลิตี้ในตัว
Kusalananda

ksh: typeset -x FOO=barแล้วecho $_พิมพ์FOOแต่ในทุบตีพิมพ์declare -x FOO=bar; echo $_ FOO=bar
ilkkachu

คำตอบ:


13

ทุบตีกระบวนการการกำหนดตัวแปรเมื่อพวกเขาได้รับอนุญาตเป็นข้อโต้แย้ง (มีalias, declare, export, local, readonlyและtypeset) ก่อนสิ่งอื่นใด (หรือมากกว่าจะระบุพวกเขาก่อนสิ่งอื่นใด - การขยายตัวนำไปใช้กับค่าที่กำหนดให้กับตัวแปร) เมื่อได้รับการขยายตัวของคำสั่งที่เหลืออยู่เป็นexport EDITORเพื่อให้มีการตั้งค่า_EDITOR

โดยทั่วไปแล้วการโต้แย้งคือ "คำ" ที่เหลือหลังจากการขยาย (ซึ่งไม่รวมการกำหนดตัวแปรและการเปลี่ยนเส้นทาง)

ดูการขยายคำสั่งอย่างง่ายในคู่มือทุบตีสำหรับรายละเอียด


และฉันก็ตระหนักถึงdeclareพฤติกรรมที่ไม่ตรงกับสิ่งที่ฉันอธิบาย ...
สตีเฟ่นคิตต์

มันไม่สอดคล้องกันมาก declare a=b; echo $_พิมพ์a=b; พิมพ์เพียงexport c=d; echo $_ ดูเหมือนว่าจะพิมพ์เพียงแค่ชื่อในทางกลับกันพิมพ์อาร์กิวเมนต์ทั้งหมด และยังพิมพ์เพียงชื่อซึ่งผมพบว่าบิตน่าแปลกใจเพราะผมจะมีความคิด และจะคล้ายกับ caliaslocalreadonlyreadonlylocaldeclare
ilkkachu

1
@ilkkachu เฮ้ฉันก็รู้เช่นกัน (ดูด้านบน) exportและreadonlyมีการประกาศร่วมกันในsetattr.def, declare, localและtypesetมีการประกาศในdeclare.def, ยืนอยู่คนเดียวalias alias.def
Stephen Kitt

ขอบคุณ เมื่อการกำหนดตัวแปรถูกใช้เป็นอาร์กิวเมนต์ของคำสั่งบางคำสั่ง (1) "(หรือมากกว่านั้นจะระบุไว้ก่อนสิ่งอื่นใด - การขยายใช้กับค่าที่กำหนดให้กับตัวแปร)" คุณหมายถึงการขยายตัวเกิดขึ้นกับค่าก่อนดำเนินการกำหนดตัวแปรหรือไม่? (2) "เมื่อได้รับการขยายคำสั่งที่เหลือคือการส่งออก EDITOR" คุณหมายถึงการดำเนินการกำหนดตัวแปรที่เกิดขึ้นก่อนที่จะขยาย? คำพูดทั้งสองดูเหมือนจะขัดแย้งกัน
ทิม

ขอบคุณ ฉันสับสนเล็กน้อย เมื่อกำหนดตัวแปรที่ใช้เป็นข้อโต้แย้งและalias, declare, export, local, readonly typesetเกิดอะไรขึ้นก่อนและต่อไป? "เมื่อได้รับการขยายคำคำสั่งที่เหลือคือexport EDITOR" คุณหมายถึงการมอบหมายตัวแปรที่EDITOR="emacs -nw"เกิดขึ้นก่อนที่จะขยาย? ถ้าไม่ใช่ทำไมคำสั่งที่เหลือไม่ได้มีการกำหนดเป็นอาร์กิวเมนต์? ถ้าใช่จะไม่เกิดการขยายค่าที่กำหนดให้กับตัวแปรก่อนที่จะทำการกำหนดตัวแปรใช่ไหม
ทิม

4

TL; DR: ในกรณีของexport FOO=barทุบตีเรียกการสร้างสภาพแวดล้อมชั่วคราวชุดในสภาพแวดล้อมที่แล้วมีผลเป็นคำสั่งสุดท้ายของFOO=bar export FOOณ จุดนั้นFOOถือเป็นอาร์กิวเมนต์สุดท้าย


อ่าผู้ที่ถูกทารุณกรรมมาก$_:

($ _, ขีดล่าง) เมื่อเริ่มต้นเชลล์ตั้งค่าชื่อพา ธ สัมบูรณ์ที่ใช้เพื่อเรียกใช้เชลล์หรือเชลล์สคริปต์ที่จะดำเนินการตามที่ส่งผ่านในสภาพแวดล้อมหรือรายการอาร์กิวเมนต์ ต่อจากนั้นขยายไปยังอาร์กิวเมนต์สุดท้ายไปยังคำสั่งก่อนหน้าหลังจากการขยาย นอกจากนี้ยังตั้งเป็นชื่อพา ธ แบบเต็มที่ใช้เพื่อเรียกใช้คำสั่งแต่ละคำสั่งที่เรียกใช้และวางไว้ในสภาพแวดล้อมที่ส่งออกไปยังคำสั่ง เมื่อตรวจสอบเมลพารามิเตอร์นี้เก็บชื่อของไฟล์เมล

ลองดูความหลากหลายของรูปแบบ:

$ man; echo $_
What manual page do you want?
man
$ man foo; echo $_
No manual entry for foo
foo
$ echo; echo $_

echo
$ echo bar foo; echo $_
bar foo
foo
$ foo=x eval 'echo $foo'; echo $_
x
echo $foo
$ bar() { man $1; }; echo $_
foo
$ for (( i=0; $i<0; i=i+1 )); do echo $i; done; echo $_
foo
$ bar; echo $_
What manual page do you want?
man
$ bar foo; echo $_
No manual entry for foo
foo
$ MANPATH=/tmp; echo $_

$ export MANPATH=/tmp; echo $_
MANPATH

ดังนั้นเราเห็นสามรูปแบบที่นี่:

  • คำสั่งที่เรียกใช้จากระบบไฟล์ฟังก์ชั่นและบิวด์อินทำงานตามที่คาดไว้: $_ตั้งค่าเป็นชื่อคำสั่งเองหากไม่มีข้อโต้แย้งมิฉะนั้นเป็นอาร์กิวเมนต์สุดท้ายที่นำเสนอ
  • หลังจากนิยามฟังก์ชัน, ลูปและการสร้างโลจิคัลอื่น ๆ : $_จะไม่ถูกแก้ไข
  • ทุกอย่างอื่น: $_ถูกตั้งค่าเป็นสิ่งที่ไม่คาดคิด แปลก.

ฉันใช้รหัสเพื่อให้ข้อมูลเชิงลึกเกี่ยวกับความแปลกประหลาด

$ ./bash --noprofile --norc -c 'man foo'
lastword=[man]
lastarg=[foo]
$ ./bash --noprofile --norc -c 'export FOO=bar'
lastword=[export]
lastarg=[FOO=bar]
bind_variable, name=[FOO], value=[bar]
before bind_lastarg, lastarg=[FOO]
bind_lastarg, arg=[FOO]
bind_variable, name=[_], value=[FOO]
$ ./bash --noprofile --norc -c 'declare FOO=bar'
lastword=[declare]
lastarg=[FOO=bar]
bind_variable, name=[FOO], value=[(null)]
before bind_lastarg, lastarg=[FOO=bar]
bind_lastarg, arg=[FOO=bar]
bind_variable, name=[_], value=[FOO=bar]

คุณสามารถเห็นได้ว่าตัวแยกวิเคราะห์เห็นอาร์กิวเมนต์สุดท้ายที่คาดไว้ ( lastarg=) ในทุกกรณี แต่สิ่งที่เกิดขึ้นหลังจากนั้นขึ้นอยู่กับสิ่งที่ทุบตีคิดว่าควรจะเกิดขึ้น ดูexecute_cmd.c, execute_simple_command ()

ในกรณีของexport FOO=barทุบตีทำการกำหนดแล้วส่งออกตัวแปร ดูเหมือนว่าสอดคล้องกับการยืนยันของเอกสารประกอบที่อาร์กิวเมนต์สุดท้ายคำนวณหลังจากการขยาย


1
เชลล์รู้ได้อย่างไรว่าคุณกำลังตรวจสอบเมล?
rackandboneman

@rackandboneman โดยไม่ต้องยืนยันฉันสงสัยว่าการตรวจสอบภายในทำตามMAILCHECK
Jeff Schaller

2

หากต้องการตอบคำถามชื่อเรื่องลอง!$:

$ export EDITOR="emacs -nw"
$ echo !$
EDITOR=emacs -nw

นี่คือการขยายประวัติ จาก manpage ทุบตี:

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

...

นักออกแบบกิจกรรม

...

! เริ่มต้นการทดแทนประวัติยกเว้นเมื่อตามด้วยบรรทัดว่างขึ้นบรรทัดใหม่การคืนค่าขนส่ง = หรือ ((เมื่อเปิดใช้งานตัวเลือกเชลล์ extglob โดยใช้ shopt builtin)

...

!! อ้างถึงคำสั่งก่อนหน้า นี่คือคำพ้องสำหรับ `! -1 '

...

โปรแกรมออกแบบคำ

...

$ คำสุดท้าย โดยปกติจะเป็นอาร์กิวเมนต์สุดท้าย แต่จะขยายเป็นคำ zeroth หากมีเพียงหนึ่งคำในบรรทัด

...

หากผู้ออกแบบคำจัดหาโดยไม่มีการกำหนดเหตุการณ์คำสั่งก่อนหน้านี้จะใช้เป็นเหตุการณ์


คุณกำลังนำหัวข้อคำถามมาด้วยเช่นกัน (ตกลงมันเป็นชื่อที่ไม่ดี) เราทุกคนเห็นว่าคำสั่ง« export EDITOR="emacs -nw"»ประกอบด้วยสองคำ: คำแรกคือ« export»และคำที่สองคือ« EDITOR="emacs -nw"» คำถามนี้ถามจริง ๆ ว่า“ หน้าคนทุบตีและคู่มือทุบตีหมายถึงอะไรเมื่อพวกเขาพูดว่า!_'ขยายไปสู่ข้อโต้แย้งสุดท้ายของคำสั่งก่อนหน้า' เนื่องจากชุดทุบตีตั้งค่า$_เป็น« EDITOR»ในกรณีนี้” การคัดลอกและวางส่วนหน้าคนทุบตีในการขยายประวัติไม่เป็นประโยชน์อย่างยิ่ง
G-Man กล่าวว่า 'Reinstate Monica'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.