ทุบตี bash สำหรับรูปแบบชื่อไฟล์หรือไดเรกทอรี


13

ฉันกำลังพยายามสร้างสคริปต์การทุบตีเสร็จสิ้นและมีปัญหา

ฉันต้องการตั้งค่าเพื่อให้รายการที่สมบูรณ์เป็นไฟล์ที่ตรงกับส่วนขยายหรือไดเรกทอรี (ซึ่งอาจมีหรือไม่มีไฟล์ของส่วนขยายนั้น)

ปัญหาที่ฉันมีคือวิธีเดียวที่ฉันจะได้รับความสำเร็จในการเก็บไฟล์และไดเรกทอรีคือการใช้สิ่งที่ชอบ-o plusdirs -f -X '!*.txt'แต่เมื่อฉันปล่อยทุบตีหนึ่งในไดเรกทอรีที่สมบูรณ์มันเพิ่งเพิ่มช่องว่างไปยังจุดสิ้นสุดมากกว่า เฉือน

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}
  local prev=${COMP_WORDS[COMP_CWORD-1]}

  #COMPREPLY=( $( compgen -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -f -G '*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o filenames -f -X '!*.txt' -- $cur ) )
  #COMPREPLY=( $( compgen -o dirnames  -f -X '!*.txt' -- $cur ) )
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
  return 0
}

complete -F _xyz xyz

ฉันได้ลองบรรทัดที่ถูกคอมเม้นต์ทั้งหมดด้วย แต่พวกเขาไม่ได้ขยายไดเรกทอรี

สำหรับการทดสอบฉันใช้งานไฟล์นี้ในไดเรกทอรีที่มีไฟล์. txt หนึ่งไฟล์และหนึ่งไดเรกทอรี "dir" (ด้วยไฟล์. txt อยู่ข้างในแม้ว่าจะยังไม่สำคัญก็ตาม) การพิมพ์xyz <TAB>ด้วยฟังก์ชั่นนี้จะแสดงรายการไดเรกทอรีและไฟล์. txt แต่การพิมพ์xyz d<TAB>จะขยายเป็นxyz dir(อย่างดีโดยมีช่องว่างหลัง "dir")

คำตอบ:


10

ถ้าคุณดูที่ฟังก์ชั่น_cd()ใน/ etc / bash_completionคุณจะเห็นว่ามันผนวกต่อท้ายเฉือนตัวเองและที่สมบูรณ์ได้รับเรียกว่ามีตัวเลือก-o nospaceสำหรับแผ่นซีดี

คุณสามารถทำเช่นเดียวกันสำหรับxyzแต่จะต้องตรวจสอบแยกต่างหากหากการจับคู่ที่พบเป็นไดเรกทอรี (ถ้าเป็นเช่นนั้นต่อท้ายทับ) หรือไฟล์ (ถ้าเป็นเช่นนั้นผนวกพื้นที่) สิ่งนี้ควรทำใน for for loop เพื่อประมวลผลการแข่งขันที่พบทั้งหมด

นอกจากนี้ในการจัดการเส้นทางที่มีช่องว่างอย่างถูกต้องคุณต้องตั้งค่าตัวคั่นไฟล์ภายในเพื่อขึ้นบรรทัดใหม่เท่านั้นและหลีกเลี่ยงช่องว่าง ใช้IFS=$'\n'ร่วมกับการprintf %qทำให้เสร็จสมบูรณ์ทำงานกับตัวละครเกือบทั้งหมด 1จะต้องมีการดูแลเป็นพิเศษเพื่อหลีกเลี่ยงการหลบหนีในพื้นที่ต่อท้าย

ต่อไปนี้ควรทำงาน:

_xyz ()
{
    local IFS=$'\n'
    local LASTCHAR=' '

    COMPREPLY=($(compgen -o plusdirs -f -X '!*.txt' \
        -- "${COMP_WORDS[COMP_CWORD]}"))

    if [ ${#COMPREPLY[@]} = 1 ]; then
        [ -d "$COMPREPLY" ] && LASTCHAR=/
        COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR")
    else
        for ((i=0; i < ${#COMPREPLY[@]}; i++)); do
            [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/
        done
    fi

    return 0
}

complete -o nospace -F _xyz xyz

1อักขระขึ้นบรรทัดใหม่เป็นข้อยกเว้นที่ชัดเจนที่นี่เนื่องจากเป็นตัวคั่นไฟล์ภายใน


มันใช้งานได้ดี (แม้ว่ามันจะแย่เกินไปก็ไม่ได้สร้างขึ้นมา) ขอบคุณ!
Rob I

1
มีเหตุผลใดที่จะไม่ใช้ "$ 2" แทนที่จะเป็น "$ {COMP_WORDS [COMP_CWORD]}" "?
Edward Falk

3

ฉันคิดว่าวิธีการแก้ปัญหาง่าย ๆ นี้ทำงานในที่:

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

กุญแจถูกส่ง-o filenamesไปให้เสร็จสมบูรณ์ สิ่งนี้ถูกทดสอบบน GNU bash 3.2.25 บน RHEL 5.3 และ GNU bash 4.3.18 บน osx

_xyz()
{
  local cur=${COMP_WORDS[COMP_CWORD]}

  local IFS=$'\n'
  COMPREPLY=( $( compgen -o plusdirs  -f -X '!*.txt' -- $cur ) )
}

complete -o filenames -F _xyz xyz

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