จำเป็นต้องใช้เครื่องหมายคำพูดสำหรับการกำหนดตัวแปรท้องถิ่นหรือไม่?


35

ฉันสามารถละเว้นการเสนอราคาทางด้านขวาของการมอบหมายงานท้องถิ่นได้อย่างปลอดภัยหรือไม่?

function foo {
    local myvar=${bar}
    stuff()
}

ฉันสนใจเป็นหลักbashแต่ข้อมูลใด ๆ ในกรณีมุมในเปลือกหอยอื่น ๆ ยินดีต้อนรับ


ฉันคิดว่ามันไม่ได้สร้างความแตกต่างถ้ามันอยู่ในหนึ่งบรรทัดเหมือนที่คุณมีในฟังก์ชั่น การมอบหมายไม่จำเป็นต้องมีการพูด ดูmpi-sb.mpg.de/departments/rg1/teaching/unixffb-ss98/…
jirib

คำตอบ:


40

คำพูดที่มีความจำเป็นในexport foo="$var"หรือlocal foo="$var"(หรือreadonly, typeset, declareและตัวแปรอื่น ๆ ประกาศคำสั่ง ) ใน:

  • dash
  • the shของ NetBSD (ตามเชลล์ Almquist ด้วย)
  • The shFreeBSD 9.2 หรือเก่ากว่า (ดูการเปลี่ยนแปลงใน 9.3 )
  • yash
  • zshกับรุ่นก่อนหน้า 5.1 ในkshหรือการshจำลอง (หรือสำหรับexport var="$(cmd)"ตำแหน่งที่zshจะทำการแยกคำอื่น ๆ (ไม่โค้ง)

มิฉะนั้นการขยายตัวของตัวแปรจะขึ้นอยู่กับการแยกคำและ / หรือการสร้างชื่อไฟล์เหมือนในอาร์กิวเมนต์ใด ๆ กับคำสั่งอื่น ๆ

และไม่จำเป็นใน:

  • bash
  • ksh (การใช้งานทั้งหมด)
  • the shFreeBSD 9.3 หรือใหม่กว่า
  • busybox 'ash-based sh(ตั้งแต่ปี 2005)
  • zsh

ในการzshแบ่ง + glob ไม่เคยทำกับการขยายพารามิเตอร์ยกเว้นในshหรือkshจำลอง แต่แยก (ไม่ใช่ glob) จะทำเมื่อมีการทดแทนคำสั่ง ตั้งแต่เวอร์ชัน 5.1, export/ localและคำสั่งการประกาศอื่น ๆ ได้กลายเป็นคำสั่งคู่คีย์เวิร์ด / builtinเช่นในเชลล์อื่น ๆ ข้างต้นซึ่งหมายความว่าไม่จำเป็นต้องมีการอ้างถึงแม้ในsh/ kshemulation และแม้กระทั่งสำหรับการทดแทนคำสั่ง

มีกรณีพิเศษที่จำเป็นต้องมีการอ้างถึงแม้ในเชลล์เหล่านั้นเช่น:

a="b=some value"
export "$a"

หรืออื่น ๆ โดยทั่วไปถ้ามีอะไรซ้ายของ=(รวม=) จะยกมาหรือผลของการขยายตัวของบางอย่าง (เช่นexport 'foo'="$var", export foo\="$var"หรือexport foo$((n+=1))="$var"(ว่า$((...))ควรที่จะยกมาจริง) ... ) หรือในคำอื่น ๆ เมื่อการโต้แย้งไปจะไม่กำหนดตัวแปรที่ถูกต้องถ้าเขียนได้โดยไม่ต้องexportexport

หากexport/ localชื่อคำสั่งตัวเองจะยกมา (แม้ในส่วนเช่น"export" a="$b", 'ex'port a="$b", \export a="$b"หรือแม้กระทั่ง""export a="$b"), คำพูดที่อยู่รอบ ๆ$bที่มีความจำเป็นยกเว้นใน AT & T และkshmksh

หากexport/ localหรือบางส่วนของมันเป็นผลมาจากการขยายตัวบางอย่าง (เช่นในcmd=export; "$cmd" a="$b"หรือแม้กระทั่งexport$(:) a="$b") หรือในสิ่งที่ชอบdryrun=; $dryrun export a="$b") แล้วคำพูดที่มีความจำเป็นในทุกเปลือก

ในกรณีของ> /dev/null export a="$b"จำเป็นต้องมีการเสนอราคาในpdkshและบางส่วนของอนุพันธ์

สำหรับcommand export a="$b", จำเป็นต้องใช้อัญประกาศในทุกเชลล์ แต่mkshและksh93(ด้วยคำเตือนเดียวกันเกี่ยวกับcommandและexportไม่เป็นผลของการขยายตัว)

พวกมันไม่ต้องการในเชลล์เมื่อเขียน:

foo=$var export foo

(ไวยากรณ์นั้นยังเข้ากันได้กับเชลล์เป้าหมาย แต่ในเวอร์ชันล่าสุดzshจะทำงานเฉพาะเมื่ออยู่ในsh/ kshจำลอง)

(โปรดทราบว่าvar=value local varไม่ควรใช้เนื่องจากพฤติกรรมแตกต่างกันไปในแต่ละเชลล์)

นอกจากนี้โปรดทราบว่าการใช้exportงานที่ได้รับมอบหมายหมายถึงสถานะทางออกของcmdin export var="$(cmd)"สูญหาย ทำตามที่export var; var=$(cmd)ไม่มีปัญหา

ยังระวังกรณีพิเศษนี้ด้วยbash:

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
ab
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b

คำแนะนำของฉันคือการพูดเสมอ


3
ทราบว่าในzshคำพูดที่จะจำเป็นสำหรับการlocal foo="$(cmd)"เพราะ wordsplitting ( แต่ไม่ใช่รุ่นชื่อไฟล์) จะดำเนินการสำหรับการแทนคำสั่ง unquoted ( แต่ไม่สำหรับการขยายพารามิเตอร์ unquoted) เว้นแต่KSH_TYPESETจะเปิดใช้งานซึ่งในคำพูดกรณีที่จะไม่จำเป็น ทำให้รู้สึก? ไม่มี? จากนั้นให้พูดทุกอย่างยกเว้นว่าคุณรู้ว่าคุณกำลังทำอะไรอยู่
Matt

2
@ Matt ฉันรักข้อสรุปของคุณ : D มันตลกมากที่สุดของสิ่งที่ฉันได้เรียนรู้การเขียนสคริปต์ของเปลือกมาจาก stackexchange นี้เพื่อที่ฉันไม่ทราบว่ามักจะพูดตัวแปรของคุณเป็นไม่ได้ที่รู้กันทั่วไปในหมู่นักเขียนบท ฉันพบว่าฉันมีจำนวนมากขึ้นอยู่กับสคริปต์การผลิตที่มีอยู่ที่เขียนโดยคนที่ไม่ได้พูดและไม่ทราบว่าสิ่งที่พวกเขากำลังทำ ....
Wildcard

3

ฉันมักจะพูดถึงการใช้งานของตัวแปรใด ๆ ที่อาจมีตัวละครเช่นช่องว่างสีขาว มิฉะนั้นคุณจะพบปัญหาเช่นนี้:

#!/bin/bash

bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"
}

foo

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

  printf "%s\n" "$myvar"

หมายเหตุ:โปรดจำไว้ว่าตัวแปร$IFSคือสิ่งที่ควบคุมว่าอักขระตัวคั่นคืออะไร

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.

ตัวอย่าง

เมื่อเปิดใช้งานการดีบักใน Bash เราจะเห็นว่าเกิดอะไรขึ้นเบื้องหลัง

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
hi
bye
+ printf '%s\n' 'hi bye'
hi bye

ในข้างต้นเราจะเห็นว่าตัวแปร$barถูกส่งไปได้ดี$myvarแต่แล้วเมื่อเราไปใช้$myvarเราจะต้องมีความรู้ความเข้าใจในเนื้อหาของ$myvarเมื่อเราไปใช้มัน


2
คำแยกไม่ได้เป็นปัญหาเฉพาะกับตัวแปร unquoted คุณต้องพิจารณารุ่นชื่อไฟล์ (aka globbing) เช่นเดียวกับ (ว่าที่ (ทั้ง) ไม่ได้นำไปใช้ในการกำหนดตัวแปรและbashและkshในlocal/ typeset... builtins พิเศษ)
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.