พารามิเตอร์การโทรที่ถูกผูกมัดกับโปรแกรมอรรถประโยชน์ใน Bash


12

ฉันมีโปรแกรมยูนิกซ์กล่องดำที่ใช้ใน Bash shell ที่อ่านคอลัมน์ข้อมูลจาก stdin ประมวลผลพวกมัน (ใช้เอฟเฟกต์การปรับให้เรียบ) จากนั้นก็ส่งออกไปยัง stdout ฉันใช้มันโดย UNIX ไพพ์เช่น

generate | smooth | plot  

สำหรับการปรับให้เรียบมากขึ้นฉันสามารถทำซ้ำแบบราบรื่นได้ดังนั้นจึงสามารถเรียกใช้จากบรรทัดคำสั่ง Bash เป็น

generate | smooth | smooth | plot   

หรือแม้กระทั่ง

generate | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | smooth | plot

นี่เป็นการไร้ค่า ฉันต้องการสร้าง Bash wrapper เพื่อให้สามารถไปป์ไลน์smoothและป้อนผลลัพธ์ของมันกลับไปสู่อินสแตนซ์ใหม่ของsmoothจำนวนครั้งโดยพลการสิ่งที่ชอบ

generate | newsmooth 5 | plot

แทน

generate | smooth | smooth | smooth | smooth | smooth | plot

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

ไม่มีข้อโต้แย้งในsmoothโปรแกรม

มีวิธีที่สง่างามกว่าในการ "ห่อ" โปรแกรมดังกล่าวเพื่อกำหนดจำนวนการโทรหรือไม่?


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

คำตอบ:


18

คุณสามารถห่อมันด้วยฟังก์ชั่นวนซ้ำ:

smooth() {
  if [[ $1 -gt 1 ]]; then # add another call to function
    command smooth | smooth $(($1 - 1)) 
  else
    command smooth # no further 
  fi
}

คุณจะใช้สิ่งนี้เป็น

generate | smooth 5 | plot

ซึ่งจะเทียบเท่ากับ

generate | smooth | smooth | smooth | smooth | smooth | plot

สิ่งนี้สมบูรณ์แบบประพฤติตรงตามความต้องการ และตอนนี้ฉันเรียนรู้เกี่ยวกับคำหลัก "คำสั่ง" bash
Diane Wilbor

2
อนึ่งนี่เป็นวิธีการเดียวกับที่ฉันใช้ในฉันจะรหัสสายโซ่ยาวโดยพลการได้อย่างไร - และนานก่อนที่จะว่าในการจัดการแก้ไขรายการที่ยาวนานใน xmlstarlet
Charles Duffy

5

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

TL; DR

บรรทัดคำสั่งทั้งหมดสำหรับกรณีตัวอย่างของคุณจะเป็น:

generate | eval 'smooth |'{,,,,} plot

บันทึก:

  • เพิ่มหรือลบเครื่องหมายจุลภาคหากคุณต้องการการทำซ้ำมากขึ้นหรือน้อยลง smooth |
  • ไม่เคยมี|มาก่อนplotเพราะนั่นรวมอยู่ในsmooth |สตริงสุดท้ายที่ผลิตโดยการขยายรั้ง
  • คุณยังสามารถระบุอาร์กิวเมนต์ได้smoothตราบใดที่คุณสามารถรวมอาร์กิวเมนต์เหล่านั้นได้อย่างถูกต้องภายในส่วนคงที่ที่ยกมาซึ่งนำหน้ารั้งเปิด ในกรณีใด ๆ จำไว้ว่าคุณต้องการจะให้พวกเขาไปทั้งหมดที่เกิดซ้ำของคำสั่ง

มันทำงานอย่างไร

การขยายตัวรั้งที่คั่นด้วยเครื่องหมายจุลภาคช่วยให้คุณสามารถสร้างสตริงแบบไดนามิกแต่ละส่วนทำจากชิ้นส่วนคงที่ที่ระบุรวมทั้งชิ้นส่วนตัวแปรที่ระบุ มันผลิตเป็นสตริงเป็นจำนวนมากมีส่วนตัวแปรที่ระบุเช่นผลิตa{b,c,d}ab ac ad

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

smooth{,,,,}

จะผลิต:

smooth smooth smooth smooth smooth

โปรดทราบว่า4เครื่องหมายจุลภาคสร้าง 5 smoothสตริง นี่เป็นเพียงวิธีการที่ Brace Expansion ใช้งานได้: มันสร้างสตริงเป็นคอมม่าจำนวนมากบวกหนึ่ง

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

'smooth|'{,,,,}

จะผลิต:

'smooth|' 'smooth|' 'smooth|' 'smooth|' 'smooth|'

ดูแลเสมอวางส่วนถาวรทันทีที่อยู่ติดกับเปิดรั้งเช่นช่องว่างระหว่างไม่มีและ' {

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

ณ จุดนี้คุณจำเป็นต้องeval ใช้กับสตริงนั้นเพื่อให้เชลล์ตีความได้ในที่สุดว่ามันเป็นคำสั่ง pipelined ที่ควรจะเป็น

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

generate | eval 'smooth |'{,,,,} plot

1
มีความกังวลด้านความปลอดภัยที่สำคัญหากมีการใช้ในสถานที่ที่มีการเรียกพารามิเตอร์ ดูคำตอบของฉันในฟังก์ชั่น Recursive bash เทียบกับการสร้างสตริง "eval" ซ้ำแล้วซ้ำอีก: ประสิทธิภาพไหนดีกว่ากัน? มากกว่าบน Stack Overflow
Charles Duffy

1
@CharlesDuffy ฉันเห็นด้วยอย่างยิ่งกับความกังวลของคุณเกี่ยวกับความเสี่ยงโดยนัยเกี่ยวกับการใช้งานevalเมื่อมีการจัดเตรียมสตริงที่ไม่น่าเชื่อถือและไม่ถูกสุขอนามัยสำหรับการประเมินนั่นคือเมื่อใช้กับตัวแปรที่อาจมีเนื้อหา "ไม่รู้จัก" เช่นกรณีที่คุณเชื่อมโยง ในทางกลับกันevalก็มีประโยชน์อย่างมากสำหรับคำสั่ง "ประปา" อย่างรวดเร็วโดยเฉพาะอย่างยิ่งเมื่อใช้ที่พรอมต์เช่นกรณีที่มือดูเหมือนจะเป็นที่evalใส่ของจะเป็นสตริงตัวอักษรที่พิมพ์ด้วยตนเองโดยผู้ใช้ใน คน
LL3

ดังที่เห็นได้จากที่อื่นคุณก็สามารถแทนที่ด้วยสิ่งเก๊กและโง่เหมือนeval str . /dev/stdin <<<strสิ่งนี้ไม่เพียง แต่จะสร้างความประทับใจให้กับคนโง่ แต่ยังจะทำให้ @CharlesDuffy หลุดจากหลังของคุณ ;-)
pizdelect

1
@pizdelect คุณอาจอ่านความคิดเห็นก่อนหน้าของ LL3 อย่างรอบคอบ - มันมีความสมดุลเหมาะสมและชาญฉลาด (อันที่จริงความคิดเห็นเริ่มต้นของฉันเองมีความแตกต่างที่คุณดูเหมือนจะไม่สนใจ; "ถ้าใช้ในกรณีที่การเรียกใช้การกำหนดพารามิเตอร์" เป็นความแตกต่างที่สำคัญ: อินสแตนซ์ของ LL3 ไม่ได้ปรับพารามิเตอร์ทำให้ปลอดภัย)
ชาร์ลส์ดัฟฟี่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.