ชื่อตัวแปรของเชลล์มียัติภังค์หรือขีดกลาง (-) หรือไม่?


38

ฉันไม่สามารถใช้-ตัวแปรในเชลล์ได้ มีวิธีที่จะใช้งานได้หรือไม่เพราะฉันมีหนึ่งสคริปต์ซึ่งขึ้นอยู่กับตัวแปรที่มีชื่อดังกล่าว:

$export a-b=c
-bash: export: `a-b=c': not a valid identifier

$export a_b=c

ก่อนโยนข้อผิดพลาดที่กำหนดและครั้งที่สองทำงานได้ดี


ไซต์ข้ามที่เป็นไปได้ซ้ำซ้อนของ: stackoverflow.com/questions/2821043/…
Ciro Santilli 事件改造中心中心法轮功六四事件

เชลล์มักจะไม่อนุญาตให้ใช้ชื่อตัวแปรดังกล่าว คุณต้องเลี่ยงผ่านเชลล์หรือแม้กระทั่งกับโปรแกรม C แบบกำหนดเองที่โหลดตัวแปรเข้าไปในสภาพแวดล้อมของ comand ของคุณ คุณไม่สามารถแก้ไขข้อผิดพลาดนี้ได้ (แม้แต่ความเสี่ยงด้านความปลอดภัยที่เป็นไปได้)?
vonbrand

คำตอบ:


47

ฉันไม่เคยพบเชลล์สไตล์ Bourne ที่อนุญาตให้ใช้-ในชื่อตัวแปร รองรับเฉพาะตัวอักษร ASCII (ในทั้งสองกรณี) _และตัวเลขและตัวอักษรตัวแรกต้องไม่เป็นตัวเลข

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

env 'strange-name=some value' myprogram

โปรดทราบว่าเชลล์บางตัว (เช่นmodern dash , mksh, zsh) ลบตัวแปรที่มีชื่อที่พวกเขาไม่ชอบจากสภาพแวดล้อม ( Shellshockทำให้คนระมัดระวังเกี่ยวกับชื่อตัวแปรสภาวะแวดล้อมดังนั้นข้อ จำกัด น่าจะเข้มงวดมากขึ้นเมื่อเวลาผ่านไปไม่อนุญาตมากขึ้น) ดังนั้นหากคุณต้องการส่งผ่านตัวแปรที่ชื่อมีอักขระพิเศษลงในโปรแกรมส่งผ่านโดยตรง โดยไม่มีเชลล์ระหว่าง ( env 'strange-name=some value' sh -c'…; myprogram'อาจหรืออาจไม่ทำงาน)


ไม่ทำงานอีกต่อไป
Jesse Glick

4
@JesseGlick ใช่แล้ว (ความคิดเห็นของคุณจะมีประโยชน์หากคุณนิยาม“ ไม่ทำงาน”: กับข้อมูลอะไรผลกระทบแทนผลที่ต้องการคืออะไรและถ้าคุณบอกว่าการใช้งานแบบใดที่envคุณใช้กับระบบปฏิบัติการใด)
Gilles หยุด ความชั่วร้าย '

ขอโทษ Ubuntu Yakkety พร้อมการอัปเดตทั้งหมด, envจากcoreutils, shจากdash: ใช้env 'with-dashes=value' bash -c 'env | fgrep dashes'งานได้ แต่env 'with-dashes=value' sh -c 'env | fgrep dashes'ไม่ได้พิมพ์อะไรเลย นั่นคือenvตัวมันเองดี แต่ดูเหมือนว่า Dash จะบล็อกตัวแปรเหล่านี้โดยเฉพาะ ดังนั้นหากโปรแกรมที่เป็นปัญหาถูกเรียกใช้ผ่าน shell wrapper ที่มี#!/bin/shส่วนหัวทั่วไปจะไม่มีวิธีที่ชัดเจนในการส่งผ่านตัวแปรดังกล่าว ตัวอย่างวิธีแก้ปัญหา
Jesse Glick

@JesseGlick นั่นคือรีบลบตัวแปร คุณต้องใช้envใกล้กับไซต์ที่เรียกของโปรแกรมที่ต้องการชื่อตัวแปรนี้โดยไม่ต้องใช้เชลล์ในระหว่างนั้น ขีดไม่ได้อยู่คนเดียวในการลบตัวแปรที่ไม่ชื่อ
Gilles 'หยุดความชั่วร้าย'

1
@JesseGlick มันเป็นความจริงที่ว่าบางสิ่งที่เคยทำงานอาจไม่ทำงานอีกต่อไปแม้ว่า: ตั้งแต่shellshockผู้คนเริ่มหัวโบราณมากขึ้นเกี่ยวกับชื่อตัวแปรและแดชก็เปลี่ยนไปจริง ๆ แล้วตั้งแต่ที่ฉันเขียนคำตอบนี้ แต่เพื่อหลีกเลี่ยงข้อผิดพลาดตามบรรทัดเดียวกัน) ฉันได้เพิ่มบันทึกคำตอบของฉันแล้ว
Gilles 'หยุดความชั่วร้าย'

15

นั่นเป็นไปไม่ได้ใน Bash

จากส่วนคำจำกัดความในหน้าคู่มือของbash:

ชื่อคำที่ประกอบด้วยตัวอักษรและตัวเลขและขีดล่างเท่านั้นและเริ่มต้นด้วยตัวอักษรหรือขีดล่าง เรียกอีกอย่างว่าตัวระบุ

จากส่วนพารามิเตอร์ในหน้าคู่มือของbash:

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


2
+1 สำหรับแสดงให้เห็นถึงประโยชน์ของ man pages อีกครั้ง
ktf

2
โพสต์เก่าที่ฉันรู้ แต่ฉันต้องการชี้ให้เห็นว่าหน้าคนที่มาใหม่อาจเป็นความลับ ฉันยังมีเวลาที่ฉันต้องการคำอธิบาย / ตัวอย่างที่ดีกว่า ใคร ๆ ก็จะโกหกถ้าพวกเขาบอกว่ามันไม่เคยเกิดขึ้นกับพวกเขา
TCZ8

1
@ TCZ8 มีเพียงคนเดียวที่บอกฉันว่าพวกเขาคิดว่า man pages คือ 'cryptic' คือคนประเภทเดียวกันที่ไม่อ่านข้อความผิดพลาดและอ่านหางอ่านทุกอย่างโดยข้ามสิ่งที่พวกเขาต้องการอ่าน
Miles Rout

13

คุณสามารถเข้าถึงตัวแปรยัติภังค์โดยใช้การอ้างอิงทางอ้อม

$ env 'my-hyphenated-variable=hello' /bin/bash
$ name='my-hyphenated-variable'
$ echo ${!name}
hello

1
ฉันไม่เคยได้ยินเกี่ยวกับฟังก์ชั่นนี้จนกว่าจะอ่านความคิดเห็นนี้ให้โซลูชันที่ง่ายกว่าสำหรับฉันมากกว่าคำตอบที่ยอมรับ
DrStrangepork

7
พฤติกรรมนี้ถูกปิดใช้งานใน bash รุ่นที่ใหม่กว่า ดูstackoverflow.com/questions/36989263/…สำหรับการวิเคราะห์สถานการณ์อย่างละเอียด
Nicolas Dudebout

6

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

คุณเคยลองใช้trเพื่อแปลงเครื่องหมายขีดคั่นเป็นขีดล่างหรือไม่?

hyphenated_name="a-b"
unhyphenated_name=$(echo $hyphenated_name | tr '-' '_')
declare -x $unhyphenated_name="some value"

Bash อนุญาตให้ '-' ปรากฏในชื่อฟังก์ชัน ฉันทำสิ่งนี้ตลอดเวลา ตัวอย่างเช่น:

function foo-bar() {
   echo "$@"
}

2

-อักขระเส้นประ ( ) เป็นตัวแบ่งและไม่ได้รับอนุญาตให้เป็นส่วนหนึ่งของชื่อตัวแปร มีวิธีแฮ็คสิ่งนี้ด้วยตัวแปรที่ยกมา แต่การแยกวิเคราะห์มันเป็นปัญหาจริงๆ นอกจากนี้ยังมีตัวละครอื่น ๆ ที่มีความหมายพิเศษในบริบทของชื่อตัวแปรใน bash, เครื่องหมายวงเล็บ, วงเล็บ, ตัวดำเนินการและเครื่องหมายคำพูด (เช่น{}()=+-&'"และอื่น ๆ )

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

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


2

คู่มือทุบตีกำหนด "ชื่อ" เป็น:

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

ดังนั้นคุณไม่สามารถใช้ยัติภังค์ในชื่อ


0

เชลล์ส่วนใหญ่รองรับเฉพาะ az, AZ, 0-9 และ _ สำหรับ variablenames อ่านรายการที่สองในหน้านี้


0

คุณสามารถเล่นกับ env และ sed

เป็นตัวอย่างฉันจำเป็นต้องอ่านตัวแปรนี้ 'ELASTICSEARCH_CLUSTER-NODES'
คำสั่ง env เอาต์พุตนี้:

~ $ env
ELASTICSEARCH_CLUSTER-NODES=elasticsearch:9200
JAVA_ALPINE_VERSION=8.212.04-r0
HOSTNAME=17eb9e7fec4c
...

ดังนั้นเพื่อแยกตัวแปร:

ESHOST=`env | sed -n 's/ELASTICSEARCH_CLUSTER-NODES=\(.*\)/\1/p'`

-1

ฉันเชื่อว่าอนุญาตให้ใช้ตัวอักษรตัวเลขและขีดล่างเท่านั้นสำหรับตัวแปร bash นี่เป็นกรณีในหลาย ๆ ภาษาโปรแกรม (จาวาสคริปต์เป็นข้อยกเว้น)

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

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


-1

คุณสามารถใช้envคำสั่งเพื่อตั้งค่าและยกเลิกการตั้งค่าตัวแปรสภาพแวดล้อมด้วย hiphens "-"

ในการตั้งคุณต้องใช้ env env commandเพื่อเรียกใช้คำสั่งของคุณ: คุณผ่านตัวแปรด้วยวิธีนี้:

env a-b=c command

เห็นมันทำงานกับ:

env a-b=c env

หรือเพื่อให้ชัดเจนขึ้น:

env a-b=c env|grep 'a-b'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.