ไปป์สำหรับเอาท์พุตป้องกันการแก้ไขตัวแปรท้องถิ่น


11

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

  1. มีคุณสมบัติชื่อไฟล์อย่างเต็มที่
  2. เรียงพวกเขา
  3. ลบรายการซ้ำ
  4. พิมพ์ทั้งหมดที่มีอยู่จริง
  5. ส่งคืนจำนวนไฟล์ที่ไม่มีอยู่

ฉันมีสคริปต์ที่เกือบจะทำในสิ่งที่ฉันต้องการ แต่ก็ล้มเหลวในการเรียงลำดับ ค่าส่งคืนของสคริปต์ตามที่ถูกต้อง แต่ผลลัพธ์ไม่ได้ (ไม่ได้เรียงลำดับและทำซ้ำ) ถ้าฉันบรรทัดเหล่า| sort -uคำสั่งตามที่ระบุเอาท์พุทที่ถูกต้อง 0แต่ค่าตอบแทนอยู่เสมอ

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

นี่คือสคริปต์:

function uniqfile
{
    local r=0 

    for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done #| sort -u    ## remove that comment

    return $r
}

เพียงสังเกตเล็ก ๆ คุณสามารถลดการfor arg in "$@" for arg"ถ้า 'ใน WORDS ... ;' ไม่มีอยู่ดังนั้นจะถือว่า 'ใน "$ @"' " - ความช่วยเหลือสำหรับ
จัดการ

คำตอบ:


15

นี่เป็นข้อผิดพลาดทุบตีที่รู้จักกันดีเนื่องจากคุณสมบัตินี้:

แต่ละคำสั่งในไปป์ไลน์จะดำเนินการเป็นกระบวนการแยกต่างหาก (เช่นใน subshell)

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

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

 for arg in "$@"
    do  
        readlink -e "$arg" || (( ++r ))

    done > >(sort -u)

ขอขอบคุณ. เยี่ยมมาก ฉันสงสัยว่าคุณจะบอกชื่อ>(..command..)โครงสร้างได้ไหม ฉันคิดว่าฉันรู้ว่ามันทำงานอย่างไร แต่รู้สึกว่าฉันควรจะอ่านเพิ่มเติม
tjm

2
@tjm: มันถูกเรียกว่าการทดแทนกระบวนการ
enzotib

การทดแทนกระบวนการใน Bash มีหลายรูปแบบ: tldp.org/LDP/abs/html/process-sub.html
slm

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

3

| sort -uกองกำลังบิตก่อนหน้า (ดังนั้นทั้งสำหรับวง) เพื่อเรียกใช้ในกระบวนการย่อย (ทุบตีต้องการ 'STDOUT' เพื่อเปลี่ยนเส้นทางเข้าสู่sort'STDIN'. (Internet ดูเหมือนจะคิดkshและbashจัดการกับกรณีนี้แตกต่างกันเล็กน้อย .. หรือนามสกุล คำสั่งในลำดับท่อได้รับใส่ลงใน subshell?)

เธรดนี้มีปัญหาที่คล้ายกันและมีวิธีแก้ไขปัญหาอย่างเรียบร้อยในตอนท้าย: http://ubuntuforums.org/showthread.php?t=312017

สิ่งที่สกัดมา
    #!/bin/bash
    exec 3< <(du | sort -n)  

    n=0
    while read size dir; do
      [ $size -gt 1000 ] && ((n++))
    done <&3
    exec 3<&-

    echo "Found $n too big files"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.