พฤติกรรมที่แปลกประหลาดของ TR ใช้ช่วง


10

ฉันมีเซิร์ฟเวอร์หนึ่งที่แสดงพฤติกรรมแปลก ๆ เมื่อใช้ tr นี่คือตัวอย่างจากเซิร์ฟเวอร์ที่ใช้งานได้:

-bash-3.2$ echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
-bash-3.2$

นั่นทำให้รู้สึกที่สมบูรณ์แบบสำหรับฉัน

อย่างไรก็ตามสิ่งนี้มาจากเซิร์ฟเวอร์ 'พิเศษ':

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

อย่างที่คุณเห็นการลบอักขระตัวพิมพ์เล็กทั้งหมดล้มเหลว แต่มันได้ลบตัวอักษร 'o'

ส่วนที่น่าสนใจคือสองตัวอย่างต่อไปนี้ซึ่งไม่สมเหตุสมผลกับฉันเลย:

[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-n]
opqrstuvwxyz1234567890
[root@host~]# echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-o]
abcdefghijklmnpqrstuvwxyz1234567890
[root@host~]#

(อีกครั้งเครื่องหมาย 'o' จะถูกลบในตัวอย่างสุดท้าย)

ไม่มีใครมีความคิดอะไรเกิดขึ้นที่นี่? ฉันไม่สามารถทำซ้ำในกล่อง linux อื่น ๆ ที่ฉันใช้


5
ที่เกี่ยวข้องกับการสัมผัส: ช่วงที่มีการเขียนโดยไม่ต้องปิดล้อมtr [...]ดังนั้นtr -d '[a-z]'จะฆ่าa-zและยังตัวอักษรและ[ ]ใช้ในการฆ่าตัวอักษรเท่านั้นtr -d a-z a-z
Satō Katsura

คำตอบ:


24

คุณมีไฟล์ชื่อoในไดเรกทอรีปัจจุบัน

foo> ls
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
1234567890
foo> touch o
foo> echo "abcdefghijklmnopqrstuvwxyz1234567890"|tr -d [a-z]
abcdefghijklmnpqrstuvwxyz1234567890

เชลล์จะขยาย[a-z]สตริงหากพบคู่ที่ตรงกัน

สิ่งนี้เรียกว่าการขยายชื่อพา ธ ตาม man bash

การขยายชื่อพา ธ
หลังจากแยกคำยกเว้นว่าตั้งค่าตัวเลือก -f แล้วทุบตีจะสแกนแต่ละคำเพื่อหาอักขระ *,? และ [ ... (... )

bash จะทำการขยายตัว

[... ] จับคู่หนึ่งในอักขระที่ล้อมรอบ


@Chris คุณสามารถตรวจสอบการขยายตัวของเชลล์โดยใช้ตัวอย่างecho: touch o ; echo tr -d [a-z]ให้สิ่งนี้:tr -d o
pabouk

8

เกิดอะไรขึ้น

เปลือก (ทุบตี) [a-z]เห็นโต้แย้ง นั่นคือรูปแบบสัญลักษณ์แทน (กglob ) ซึ่งตรงกับletter¹พิมพ์เล็ก ๆ ดังนั้นเชลล์จะค้นหาชื่อไฟล์ที่ตรงกับรูปแบบนี้ มีสามกรณี:

  • ไม่มีไฟล์ในไดเรกทอรีปัจจุบันที่มีชื่อที่เป็นอักษรตัวพิมพ์เล็กตัวเดียว แล้วเปลือกใบรูปแบบสัญลักษณ์แทนไม่เปลี่ยนแปลงและtrเห็นขัดแย้งและ-d [a-z]นี่คือสิ่งที่เกิดขึ้นในเครื่องส่วนใหญ่ของคุณ
  • ไฟล์เดียวในไดเรกทอรีปัจจุบันมีชื่อที่เป็นอักษรตัวพิมพ์เล็กเดียว จากนั้นเชลล์จะขยายรูปแบบเป็นชื่อไฟล์นี้และtrเห็นอาร์กิวเมนต์-dและชื่อไฟล์ นี้เกิดขึ้นบนเซิร์ฟเวอร์และไฟล์การจับคู่ที่เรียกว่าoตั้งแต่ที่เราจะเห็นได้ว่าลบตัวอักษรtro
  • ไฟล์อย่างน้อยสองไฟล์ในไดเรกทอรีปัจจุบันมีชื่อที่เป็นอักษรตัวพิมพ์เล็กหนึ่งตัว จากนั้นเชลล์จะขยายรูปแบบไปยังรายการชื่อไฟล์ที่ตรงกันและtrเห็นอาร์กิวเมนต์สามตัวขึ้นไป: -dและชื่อไฟล์ เนื่องจากtrคาดว่าจะมีการโต้แย้งเพียงครั้งเดียวหลังจาก-dนั้นมันจะบ่น

สิ่งที่คุณควรทำ

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

tr -d '[a-z]'

อย่างไรก็ตามโปรดทราบว่านี่อาจจะไม่ใช่สิ่งที่คุณหมายถึง! สิ่งนี้บอกtrให้ลบตัวอักษรตัวเล็กและเครื่องหมายวงเล็บเหลี่ยม มันเทียบเท่ากับtr -d ']a-z[', tr '[]a-z'ฯลฯ หากต้องการลบตัวอักษรพิมพ์เล็กให้ใช้

tr -d a-z

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

คุณไม่จำเป็นต้องวงเล็บเพื่อระบุตัวละครคลาส ในนิพจน์ทั่วไปคุณใช้วงเล็บในวงเล็บเพื่อระบุคลาสอักขระเช่น[[:lower:]]*จับคู่ตัวอักษรตัวพิมพ์เล็ก[[:lower:]_]*จำนวนใด ๆ จับคู่ตัวอักษรตัวเล็กและขีดล่าง ในอาร์กิวเมนต์ของtrคุณต้องตั้งค่าโดยไม่มีเครื่องหมายวงเล็บล้อมรอบดังนั้นจึงต้องtr -d '[:lower:]'ลบตัวอักษรตัวtr -d '[:lower:]_'พิมพ์เล็กลบตัวอักษรตัวเล็กและเครื่องหมายขีดล่าง ฯลฯ

¹ ในบางที่มันอาจจะตรงกับตัวละครอื่น


1
โปรดทราบว่าบน Solaris 10 (และอื่น ๆ Unices SysV โบราณ based) คุณไม่จำเป็นต้องมีtr -d '[a-z]' /usr/bin/trด้วย/usr/xpg4/bin/tr, tr -d a-zทำงาน แต่tr -d '[a-z]'ไม่ได้ลบมิได้[ ]
Stéphane Chazelas

1
/usr/xpg4/bin/tr -d '[a-z]'ไม่ได้ลบ[และไม่]ได้รับการแก้ไขใน Solaris 11
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.