% ทำอะไรในสตริงเชลล์ของ Linux?


28

ในเชลล์ Linux สิ่งที่% ทำเช่นเดียวกับใน:

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

4
ทุกครั้งที่ค้นหานี้ฉันมักจะพบส่วนที่ถูกต้องของหน้า bash man ด้วยการค้นหา%%หรือ##เนื่องจากเป็นสิ่งที่น่าจดจำและหายากพอที่จะหาส่วนที่เหมาะสมได้อย่างรวดเร็ว man bash /##
Peter Cordes

3
@ PeterCordes ฉันมักจะจำสิ่งนี้โดย "มันเป็น 5% ดังนั้น% อยู่ในตอนท้ายและลดลงจากจุดสิ้นสุดและมันคือ # 5 ดังนั้น # อยู่ที่จุดเริ่มต้นและตัดจากจุดเริ่มต้น" แต่บางครั้งฉันก็รวมอันนี้ ...
glglgl

2
@glglgl: บนแป้นพิมพ์ USA ทั่วไป#จะอยู่ทางซ้ายทันที$และ%อยู่ทางขวาทันที ไม่จำเป็นช่วยในการจำเพียงแค่มองลงไป (นั่นอาจเป็นเหตุผลส่วนหนึ่งที่ทำให้สัญลักษณ์เหล่านั้นถูกเลือก)
Kevin J. Chase

@ KevinJ.Chase ไม่ใช่ทุกคนทั่วโลกที่มีแป้นพิมพ์ USA ทั่วไป แต่ที่จริงแล้วบนแป้นพิมพ์ภาษาเยอรมัน% นั้นถูกต้อง $ เช่นกันซึ่งอาจเป็นการเริ่มต้นสำหรับการบันทึกความจำ
glglgl

คำตอบ:


29

เมื่อ%ถูกนำมาใช้ในรูปแบบ${variable%substring}ก็จะกลับเนื้อหาของvariableกับ occurance ที่สั้นที่สุดของถูกลบออกจากด้านหลังของsubstringvariable

ฟังก์ชั่นนี้รองรับรูปแบบไวด์การ์ด - นั่นคือเหตุผลที่มันยอมรับดาว (เครื่องหมายดอกจัน) เป็น substite สำหรับอักขระศูนย์หรือมากกว่า

มันควรจะกล่าวว่านี่เป็น Bash specific - เชลล์ linux อื่นไม่จำเป็นต้องมีฟังก์ชั่นนี้

หากคุณต้องการที่จะเรียนรู้เพิ่มเติมเกี่ยวกับการจัดการสตริงในทุบตีผมขอแนะนำให้อ่านนี้หน้า ในบรรดาฟังก์ชั่นที่ใช้งานสะดวกอื่น ๆ ของมัน - ตัวอย่าง - อธิบายสิ่งที่%%ทำ :)

แก้ไข: ฉันลืมที่จะพูดถึงว่าเมื่อมันมาใช้ในรูปแบบ$((variable%number))หรือตัวละครที่จะทำหน้าที่เป็นผู้ประกอบการโมดูโล DavidPostill มีลิงก์เอกสารเฉพาะเพิ่มเติมในคำตอบของเขา$((variable1%$variable2))%

เมื่อ%มีการใช้งานในบริบทที่แตกต่างกันมันควรได้รับการยอมรับว่าเป็นตัวอักษรปกติเท่านั้น


2
โอเปอเรเตอร์รองรับรูปแบบไวด์การ์ดไม่ใช่นิพจน์ทั่วไป
Gardenhead

เช่นเดียวกับ Gardenhead ที่กล่าวถึง - มันรองรับรูปแบบ glob ไม่ใช่การแสดงออกปกติ ในการแสดงออกปกติดาวหมายถึงศูนย์หรือมากกว่าของตัวละครก่อนหน้า
slebetman

5
คู่มือที่คุณได้เชื่อมโยงกับการเป็นอย่างมากไม่แนะนำโดยส่วนใหญ่ Unix และ Linux ผู้ใช้แลกเปลี่ยนสแต็ค ฉันแนะนำWoolash Bash Guideแทน
สัญลักษณ์แทน

3
คำนำหน้าและตัวดำเนินการลบคำต่อท้ายเป็นมาตรฐานดังนั้นจึงควรใช้งานได้ในshเชลล์ที่เข้ากันได้ใด ๆไม่ใช่ Bash เท่านั้น (แม้ว่าอาจจะไม่ใช่cshและไม่ชอบ)
ilkkachu

1
บริบทที่อีก%เป็นสินค้าที่อยู่ใน specifiers printfรูปแบบ
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

9

คู่มืออ้างอิง Bash: การขยายพารามิเตอร์เชลล์

${parameter%word}
${parameter%%word}

คำมีการขยายการผลิตรูปแบบเช่นเดียวกับการขยายตัวในชื่อไฟล์ หากรูปแบบตรงกับส่วนต่อท้ายของค่าส่วนขยายของพารามิเตอร์ผลลัพธ์ของการขยายคือค่าของพารามิเตอร์ที่มีรูปแบบการจับคู่ที่สั้นที่สุด ( ‘%’เคส) หรือรูปแบบการจับคู่ที่ยาวที่สุด ( ‘%%’เคส) ถูกลบ หากพารามิเตอร์คือ‘@’หรือ‘*’,การดำเนินการลบรูปแบบถูกนำไปใช้กับแต่ละพารามิเตอร์ตำแหน่งในทางกลับกันและการขยายตัวเป็นรายการผลลัพธ์ ถ้าพารามิเตอร์เป็นตัวแปรอาร์เรย์ห้อยด้วย‘@’ หรือ‘*’, การดำเนินการลบรูปแบบจะถูกนำไปใช้กับสมาชิกแต่ละคนของอาร์เรย์ในทางกลับกันและการขยายตัวเป็นรายการผลลัพธ์


2
NB การขยายพารามิเตอร์บางตัวรวมถึง% เป็นคุณสมบัติ posix ที่เชลล์จำนวนมากสนับสนุน
kojiro

7

จากการทดลองฉันพบว่าการจับคู่หลังจาก% ถูกยกเลิกเมื่อสตริงนั้นอยู่ในวงเล็บปีกกา (วงเล็บปีกกา)

เพื่อแสดง:

touch abcd         # Create file abcd

for file in ab*; do
 echo $file        # echoes the filename
 echo $file%       # echoes the filename plus "%"
 echo ${file%}     # echoes the filename
 echo "${file%}"   # echoes the filename
 echo
 echo "${file%c*}" # Discard anything after % matching c*
 echo "${file%*}"  # * is not greedy
 echo ${file%c*}   # Without quotes works too
 echo "${file%c}"  # No match after %, no effect
 echo $file%c*     # Without {} fails
done

นี่คือผลลัพธ์:

abcd
abcd%
abcd
abcd

ab
abcd
ab
abcd
abcd%c*

7

ใน Linux shell ( bash) จะ%ทำอะไร?

for file in *.png.jpg; do
  mv "$file" "${file%.png.jpg}.jpg"
done

ในกรณีนี้ตัวดำเนินการ%คือการจับคู่รูปแบบ (โปรดทราบว่ามันสามารถเป็นตัวดำเนินการแบบโมดูโลได้ )


ผู้ประกอบการจับคู่รูปแบบ

$ {var% $ Pattern}, $ {var %% $ Pattern}

${var%$Pattern}ลบออกจาก$varส่วนที่สั้นที่สุดของที่ตรงปลายด้านหลังของ$Pattern$var

${var%%$Pattern}ลบออกจาก$varส่วนที่ยาวที่สุดของที่ตรงปลายด้านหลังของ$Pattern$var

ตัวอย่าง: การจับคู่รูปแบบในการทดแทนพารามิเตอร์

#!/bin/bash
# patt-matching.sh

# Pattern matching  using the # ## % %% parameter substitution operators.

var1=abcd12345abc6789
pattern1=a*c  # * (wild card) matches everything between a - c.

echo
echo "var1 = $var1"           # abcd12345abc6789
echo "var1 = ${var1}"         # abcd12345abc6789
                              # (alternate form)
echo "Number of characters in ${var1} = ${#var1}"
echo

echo "pattern1 = $pattern1"   # a*c  (everything between 'a' and 'c')
echo "--------------"
echo '${var1#$pattern1}  =' "${var1#$pattern1}"    #         d12345abc6789
# Shortest possible match, strips out first 3 characters  abcd12345abc6789
#                                     ^^^^^               |-|
echo '${var1##$pattern1} =' "${var1##$pattern1}"   #                  6789      
# Longest possible match, strips out first 12 characters  abcd12345abc6789
#                                    ^^^^^                |----------|

echo; echo; echo

pattern2=b*9            # everything between 'b' and '9'
echo "var1 = $var1"     # Still  abcd12345abc6789
echo
echo "pattern2 = $pattern2"
echo "--------------"
echo '${var1%pattern2}  =' "${var1%$pattern2}"     #     abcd12345a
# Shortest possible match, strips out last 6 characters  abcd12345abc6789
#                                     ^^^^                         |----|
echo '${var1%%pattern2} =' "${var1%%$pattern2}"    #     a
# Longest possible match, strips out last 12 characters  abcd12345abc6789
#                                    ^^^^                 |-------------|

# Remember, # and ## work from the left end (beginning) of string,
#           % and %% work from the right end.

echo

exit 0

การทดแทนพารามิเตอร์แหล่งที่มา


ผู้ประกอบการโมดูโล่

%

modulo หรือ mod (ส่งคืนส่วนที่เหลือของการดำเนินการหารจำนวนเต็ม)

bash$ expr 5 % 3
2

5/3 = 1, ที่เหลือ 2

ผู้ประกอบการที่มา


บางทีฉันอาจได้รับ: นี่เป็นสิ่งที่ชอบ.*และ%กำหนดให้ไม่ใช่โลภในขณะที่%%ทำให้มันโลภ? จริงๆแล้วในตัวอย่างการเปลี่ยนชื่อมันไม่สำคัญว่าจะใช้%หรือ%%แต่ถ้าเป็นmv "$file" "${file%.*png.jpg}.jpg"(หมายเหตุ *) โดยใช้ %% จะเปลี่ยนชื่อไฟล์ทั้งหมดเป็นเพียง.jpgใช่มั้ย
โทมัสเวลเลอร์

@ThomasWeller ฉันคิดว่าถูกต้อง แต่ฉันไม่มีผู้เชี่ยวชาญทุบตี
DavidPostill

พูดว่า "เอาออก ... ส่วนที่สั้นที่สุดของ$Pattern" เป็นสิ่งที่ผิดเป็นตัวแปร$Patternไม่ได้กำหนดไว้ในตัวอย่างเฉพาะข้อความ "รูปแบบ" จะถูกลบออกจาก$varเมื่อทำหรือ${var%Pattern} ${var%%Pattern}บางทีนี่อาจเป็นแค่ตัวพิมพ์ผิด แต่ก็เป็นอีกตัวอย่างหนึ่งของ tldp.org ที่ผิด BashGuideหรือBash Hackers Wikiเป็นทั้งการอ้างอิงที่ดีกว่ามาก
John B

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