วิธีใช้ตัวแปรสภาพแวดล้อมภายในสตริงที่ยกมาใน Bash


95

ฉันได้ลองใช้รูปแบบต่างๆต่อไปนี้ใน bash script:

#!/bin/bash
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

แต่ฉันไม่สามารถรับไวยากรณ์เพื่อขยายCOLUMNSตัวแปรสภาพแวดล้อมได้อย่างถูกต้อง

ฉันได้ลองใช้รูปแบบต่างๆดังต่อไปนี้:

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W $COLUMNS'

และ

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W ${COLUMNS}'

และ

eval svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

ข้อเสนอแนะ?


แล้วตัวอย่างเหล่านั้นก่อให้เกิดอะไรในกรณีของคุณ? และคุณต้องการให้พวกเขาผลิตอะไร?

คำสั่งนอกสคริปต์ใช้งานได้หรือไม่
dfa

คุณได้ลองsvn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Qian Chen

BTW โดยใช้$@unquoted ทำให้เหมือนกับ$*- ซึ่งกล่าวได้ว่าแบ่ง"foo bar"ออกเป็นสองอาร์กิวเมนต์แยกกันfooและbar. "$@"หากคุณต้องการที่จะรักษารายการอาร์กิวเมนต์เดิมเช่นเดียวกับที่ได้รับกับคุณคุณต้องการ
Charles Duffy

ดูความแตกต่างระหว่างคำพูดเดี่ยวและคู่ในทุบตี
codeforester

คำตอบ:


16

หากไม่แน่ใจคุณอาจใช้คำขอ 'cols' บนเครื่องเทอร์มินัลและลืม COLUMNS:

COLS=$(tput cols)

ไม่ว่าด้วยเหตุผลใดนี่เป็นทางออกเดียวที่ฉันสามารถแก้ไขได้จากหน้านี้ (ณ วันที่ 11/10 พฤษภาคม ET) ขอบคุณ
เจมี่

407

เพียงบันทึกสั้น ๆ / สรุปสำหรับทุกคนที่มาที่นี่ผ่าน Google ที่กำลังมองหาคำตอบสำหรับคำถามทั่วไปที่ถามในชื่อเรื่อง (เหมือนฉัน) สิ่งต่อไปนี้ควรใช้เพื่อเข้าถึงตัวแปรเชลล์ภายในเครื่องหมายคำพูด:

echo "$VARIABLE"
echo "${VARIABLE}"

การใช้เครื่องหมายคำพูดเดี่ยวเป็นประเด็นหลัก ตามคู่มืออ้างอิง Bash :

การใส่อักขระในเครื่องหมายคำพูดเดี่ยว ( ') จะรักษาค่าที่แท้จริงของแต่ละอักขระภายในเครื่องหมายคำพูด เครื่องหมายคำพูดเดียวอาจไม่เกิดขึ้นระหว่างเครื่องหมายคำพูดเดี่ยวแม้ว่าจะนำหน้าด้วยแบ็กสแลชก็ตาม [ ... ] อักขระล้อมรอบในราคาคู่ ( ") เก็บรักษามูลค่าที่แท้จริงของตัวละครทุกตัวที่อยู่ในคำพูดที่มีข้อยกเว้นของ$, `, และเมื่อการขยายตัวประวัติถูกเปิดใช้งาน\ !อักขระ$และ `คงความหมายพิเศษไว้ในเครื่องหมายคำพูดคู่ (ดูการขยายเชลล์) เครื่องหมายยังคงมีความหมายพิเศษเฉพาะเมื่อตามด้วยหนึ่งในตัวละครต่อไปนี้: $, `, ",\หรือขึ้นบรรทัดใหม่ ภายในเครื่องหมายคำพูดคู่แบ็กสแลชที่ตามด้วยอักขระเหล่านี้จะถูกลบออก แบ็กสแลชที่นำหน้าอักขระที่ไม่มีความหมายพิเศษจะถูกปล่อยทิ้งไว้โดยไม่มีการแก้ไข อัญประกาศคู่อาจยกมาภายในเครื่องหมายคำพูดคู่โดยนำหน้าด้วยแบ็กสแลช หากเปิดใช้งานการขยายประวัติจะดำเนินการเว้นแต่การ!ปรากฏในเครื่องหมายคำพูดคู่จะถูกใช้ Escape โดยใช้แบ็กสแลช แบ็กสแลชที่อยู่ข้างหน้า!จะไม่ถูกลบออก พารามิเตอร์พิเศษ*และ@มีความหมายพิเศษเมื่ออยู่ในเครื่องหมายอัญประกาศคู่ (ดูการขยายพารามิเตอร์เชลล์)

ในกรณีเฉพาะที่ถามในคำถาม $ COLUMNS เป็นตัวแปรพิเศษที่มีคุณสมบัติที่ไม่เป็นมาตรฐาน (ดูคำตอบของ lhunath ด้านบน)


20
ในกรณีของเครื่องหมายคำพูดเดี่ยววิธีแก้ปัญหาอาจช่วยได้: 'before'"$variable"'after'(ตามที่ระบุไว้ในคำตอบนี้: stackoverflow.com/a/13802438/2254346 )
MakisH

ตอบโจทย์มาก! ฉันมีปัญหาเดียวกันในการอ้างอิงตัวแปร env ของฉันภายในเครื่องหมายคำพูดเดียว เมื่อฉันเปลี่ยนใบเสนอราคาเดี่ยวเป็นอัญประกาศคู่ตัวแปร env ของฉันก็ถูกขยายตามที่คาดไว้
Binita Bharati

14

โปรดทราบว่าCOLUMNS:

  1. ไม่ใช่ตัวแปรสภาพแวดล้อม เป็นพารามิเตอร์ bash ธรรมดาที่กำหนดโดย bash เอง
  2. ตั้งค่าโดยอัตโนมัติเมื่อได้รับSIGWINCHสัญญาณ

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

หากสคริปต์ของคุณstdinเชื่อมต่อกับเทอร์มินัลของคุณคุณสามารถค้นหาความกว้างของเทอร์มินัลได้ด้วยตนเองโดยถามเทอร์มินัลของคุณ:

tput cols

และใช้สิ่งนี้ในคำสั่ง SVN ของคุณ:

svn diff "$@" --diff-cmd /usr/bin/diff -x "-y -w -p -W $(tput cols)"

(หมายเหตุ: คุณควรพูด "$@"และอยู่ห่างจากeval;-))


ขอบคุณสำหรับข้อมูล; การรู้ว่าเกิดอะไรขึ้นทำให้เกิดความรู้สึกเป็นพิษต่อปัญหา
Jamie

2

สคริปต์ต่อไปนี้ใช้ได้กับฉันสำหรับค่าต่างๆของ$COLUMNS. ฉันสงสัยว่าคุณไม่ได้ตั้งค่าCOLUMNSก่อนการโทรนี้?

#!/bin/bash
COLUMNS=30
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

คุณสามารถสะท้อน$COLUMNSภายในสคริปต์ของคุณเพื่อดูว่าตั้งค่าถูกต้องหรือไม่?


Boo, hiss re: unquoted $@- ซึ่งแยกพารามิเตอร์เดียว"two words"ออกเป็นสองพารามิเตอร์แยกกันtwoและwords. ควรจะ"$@"ส่งผ่านรายการอาร์กิวเมนต์ให้ตรงตามที่ระบุไว้
Charles Duffy

0

คุณทำถูกต้องดังนั้นฉันคิดว่ามีอย่างอื่นที่ผิดพลาด (ไม่ใช่คอลัมน์การส่งออก?)

เคล็ดลับในการดีบักกรณีเหล่านี้คือการสร้างคำสั่งพิเศษ (การปิดสำหรับคนภาษาโปรแกรม) สร้างเชลล์สคริปต์ชื่อ diff-column ทำ:

exec /usr/bin/diff -x -y -w -p -W "$COLUMNS" "$@"

และใช้เพียง

svn diff "$@" --diff-cmd  diff-columns

วิธีนี้ทำให้โค้ดของคุณอ่านง่ายขึ้นและเป็นโมดูลาร์มากขึ้น (วิธีการจากบนลงล่าง) และคุณสามารถทดสอบโค้ด diff-column แยกกันได้โดยแยกกัน (วิธีจากล่างขึ้นบน)


บรรทัดคำสั่งจะถูกแยกวิเคราะห์ก่อนที่กระบวนการจะถูกแยกดังนั้นการไม่เอ็กซ์พอร์ต COLUMNS จึงไม่ใช่ปัญหา
Peter van der Heijden

1
เขาบอกว่ารหัสของเขาเป็นส่วนหนึ่งของสคริปต์ทุบตีดังนั้นจึงอาจเป็นปัญหาได้
Colas Nahaboo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.