รูปแบบชื่อไฟล์เชลล์ที่ขยายเป็น dot files แต่ไม่ใช่ `.. '


13

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

chown -R root .*

ตามธรรมชาติแล้วการ.*ขยายไปสู่..ภัยพิบัติ

ฉันรู้ว่าในbashพฤติกรรมนี้สามารถเปลี่ยนแปลงได้โดยการปรับแต่งตัวเลือกเชลล์บางอย่าง แต่ด้วยการตั้งค่าเริ่มต้นจะมีรูปแบบใดที่จะขยายไปยังทุก ๆ จุดไฟล์ในไดเรกทอรี แต่ไม่ใช่.และ..?

คำตอบ:


20

Bash, ksh และ zsh มีวิธีแก้ปัญหาที่ดีกว่า แต่ในคำตอบนี้ฉันถือว่า POSIX เชลล์

รูปแบบ.[!.]*จับคู่ไฟล์ทั้งหมดที่ขึ้นต้นด้วยจุดตามด้วยอักขระที่ไม่ใช่จุด (โปรดทราบว่า[^.]เชลล์บางตัวรองรับ แต่ไม่ใช่ทั้งหมดไวยากรณ์แบบพกพาสำหรับชุดอักขระในรูปแบบไวด์การ์ดคือ[!.]) ดังนั้นจึงไม่รวม.และ..แต่ยังไฟล์ที่ขึ้นต้นด้วยสองจุด รูปแบบไฟล์ที่จับที่ขึ้นต้นด้วยสองจุดและไม่เพียง..?*..

chown -R root .[!.]* ..?*

นี่คือรูปแบบดั้งเดิมที่ตั้งค่าไว้เพื่อให้ตรงกับไฟล์ทั้งหมด:

* .[!.]* ..?*

ข้อ จำกัด ของวิธีการนี้คือถ้ารูปแบบใดรูปแบบหนึ่งตรงกับสิ่งใดมันจะถูกส่งไปยังคำสั่ง ในสคริปต์เมื่อคุณต้องการจับคู่ไฟล์ทั้งหมดในไดเรกทอรียกเว้น.และ..มีวิธีแก้ปัญหาต่าง ๆ ทั้งหมดนั้นยุ่งยากทั้งหมด:

  • ใช้* .*เพื่อระบุรายการทั้งหมดและไม่รวม.และ..เป็นลูป หนึ่งหรือทั้งสองรูปแบบอาจไม่ตรงกับสิ่งใดดังนั้นลูปจำเป็นต้องตรวจสอบการมีอยู่ของแต่ละไฟล์ คุณมีโอกาสกรองตามเกณฑ์อื่น ๆ ตัวอย่างเช่นลบการ-hทดสอบหากคุณต้องการข้ามลิงค์สัญลักษณ์ห้อยต่องแต่ง

    for x in * .*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • ตัวแปรที่ซับซ้อนกว่าซึ่งคำสั่งรันเพียงครั้งเดียว โปรดทราบว่าพารามิเตอร์ตำแหน่งถูกปิดกั้น (POSIX เชลล์ไม่มีอาร์เรย์) ใส่สิ่งนี้ในฟังก์ชั่นแยกต่างหากถ้านี่เป็นปัญหา

    set --
    for x in * .[!.]* ..?*; do
      case $x in .|..) continue;; esac
      [ -e "$x" ] || [ -h "$x" ] || continue
      set -- "$@" "$x"
    done
    somecommand "$@"
  • ใช้อันมี* .[!.]* ..?*ค่า อีกรูปแบบหนึ่งรูปแบบอาจไม่ตรงกันดังนั้นเราจึงต้องตรวจสอบไฟล์ที่มีอยู่ (รวมถึงลิงก์สัญลักษณ์ห้อยต่องแต่ง)

    for x in * .[!.]* ..?*; do
      [ -e "$x" ] || [ -h "$x" ] || continue
      somecommand "$x"
    done
  • ใช้* .[!.]* ..?*tryptich และเรียกใช้คำสั่งหนึ่งครั้งต่อรูปแบบ แต่ถ้าตรงกับบางสิ่งเท่านั้น สิ่งนี้รันคำสั่งเพียงครั้งเดียว โปรดทราบว่าพารามิเตอร์ตำแหน่งถูกปิดกั้น (เชลล์ POSIX ไม่มีอาร์เรย์) วางสิ่งนี้ไว้ในฟังก์ชันที่แยกต่างหากถ้านี่เป็นปัญหา

    set -- *
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- .[!.]* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    set -- ..?* "$@"
    [ -e "$1" ] || [ -h "$1" ] || shift
    somecommand "$@"
  • findใช้ ด้วย GNU หรือ BSD หาหลีกเลี่ยงการเรียกซ้ำเป็นเรื่องง่ายด้วยตัวเลือกและ-mindepth -maxdepthด้วย POSIX พบว่ามันมีเล่ห์เหลี่ยมเล็กน้อย แต่สามารถทำได้ แบบฟอร์มนี้มีข้อดีของการอนุญาตให้เรียกใช้คำสั่งได้อย่างง่ายดายในครั้งเดียวแทนที่จะเป็นหนึ่งครั้งต่อไฟล์ (แต่ไม่รับประกันว่า: หากคำสั่งผลลัพธ์ยาวเกินไปคำสั่งจะทำงานในหลายแบตช์)

    find . -name . -o -exec somecommand {} + -o -type d -prune

6

ใช้งานได้หากชื่อไฟล์ทั้งหมดมีอักขระอย่างน้อยสามตัว (รวมถึงจุด):

chown -R root .??*

สำหรับโซลูชันที่แข็งแกร่งกว่านี้คุณสามารถใช้find:

find . -maxdepth 1 -name '.*' -exec chown -R root {} \;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.