บล็อกนี้ทำด้วย Hugo เก็บ content ที่เป็นโพสต์ต่างๆ ไว้ในโฟลเดอร์ content/post/<POST_NAME>/
แต่ยังมีโพสต์เก่าๆ ที่ยังไม่ได้อยู่ในโฟลเดอร์ของตัวเอง หลงเหลืออยู่ เป็นโพสต์ที่ย้ายมาจากบล็อก Jekyll เมื่อก่อนนู้น
ชื่อไฟล์จะอยู่ในรูปแบบ YYYY-MM-DD-post-slug.markdown
อยากจัดระเบียบให้มันเหมือนๆ กัน เป็นงานที่ดองไว้นานแล้วแต่ไม่ได้ทำ
ภารกิจ
ภารกิจคือ ย้ายไฟล์
- จาก
content/post/2011-03-29-hello-world.markdown - ไป
content/post/hello-world/index.md
ซึ่งมีไฟล์ต้องย้ายอยู่ 140 กว่าไฟล์ ถ้าต้องมาสร้างโฟลเดอร์ใหม่ และย้ายไฟล์เองด้วยมือทุกไฟล์ คงเป็นงานที่น่าเบื่อน่าดู
ผมมีความคิดจะเขียน shell script ขึ้นมาเพื่อ automate process นี้
ถึงแม้ว่าผมจะเขียน shell script ไม่เป็น แต่เพราะไม่อยากทำงานซ้ำๆ ก็เลยใช้โอกาสนี้ในการเรียนรู้ใหม่อีกครั้ง
(ผมเคยเรียนเขียน shell script ในวิชา basic linux ตอนเรียนมหาลัยปี 2 แต่ก็ลืมไปหมดแล้ว) 😅
วางแผน
- ใช้ shell script
- loop ไฟล์
.markdownทั้งหมดในโฟลเดอร์content/post/ - ตัดส่วนวันที่ออกจากชื่อไฟล์
20xx-xx-xx-(เอาออกได้เพราะข้อมูลวันที่อยู่ใน front-matter ของแต่ละไฟล์อยู่แล้ว) - ตัดส่วน extension
.markdownออกจากชื่อไฟล์ - ก็จะเหลือ post slug ตรงกลาง สร้างโฟลเดอร์ใหม่จากชื่อนี้
- ย้ายไฟล์
.markdownไปเป็นindex.mdในโฟลเดอร์ที่สร้างใหม่
1. สร้างไฟล์ script
ผมเริ่มจากการสร้างไฟล์ shell script ไว้ข้างในโฟลเดอร์เดียวกับไฟล์ที่จะทำงาน
พร้อมกับทำให้มันรันได้ ด้วยการเปลี่ยน permission เป็น +x (executable)
$ cd content/post/
$ touch rename.sh
$ chmod +x rename.sh
คุ้นๆ ว่าในบรรทัดแรกของ shell script มันต้องมีอะไรพิเศษสักอย่าง
เลยเสิชกูเกิลด้วย keyword bash first line
ก็พบว่า บรรทัดนั้นคือ shebang หรือ sha-bang หรือ hashbang
มีไว้เลือก shell ว่าจะรัน script ใน shell ไหน
ผมเลือก bash ไว้ก่อนเพราะคิดว่าเซฟสุด
#!/bin/bash
2. loop ไฟล์ .markdown
จากนั้นก็เสิชหาวิธีการ loop ไฟล์ในโฟลเดอร์นั้นทำยังไงด้วย keyword: bash list files in directory
เจอคำตอบจาก StackOverflow
ก็คือใช้ command ls นั่นเอง
#!/bin/bash
markdownfiles=`ls *.markdown`
for file in $markdownfiles
do
# something ...
echo $file
done
- list file markdown ด้วย
ls - ใช้
`(backtick) เพื่อเก็บ output จาก command ไว้ใน variable - จากนั้น loop ด้วย
for ... in - เปิด block ด้วย
doจบด้วยdone - เวลาสร้าง variable ไม่ต้องใช้
$แต่เวลาเรียกใช้ ต้องมี$ข้างหน้า - เว้นวรรคตรงเครื่องหมาย
=ไม่ได้ ต้องเขียนติดกัน (เว้นวรรคถือว่าเป็น argument ของ command)
3. ตัดวันที่ชื่อออกจากชื่อไฟล์
วันที่ในชื่อไฟล์อยู่ใน pattern เดียวกันหมด คือ นำหน้าด้วย YYYY-MM-DD-
เป็นตัวอักษร 11 ตัวแรกของชื่อไฟล์ ก็ใช้วิธีบ้านๆ เลย คือ การตัด string
ผมเสิชหาด้วย keyword bash cut string เจอกระทู้ใน StackOverflow อีกแล้ว
#!/bin/bash
markdownfiles=`ls *.markdown`
for file in $markdownfiles
do
filename=${file:11}
done
${file:11}ตัดตัวอักษร 11 ตัวแรก แล้ว return ส่วนที่เหลือ- แต่ถ้าเป็น
${file::11}(มี:สองอัน) คือตัดเอาเฉพาะ 11 ตัวแรก
4. ตัด .markdown ออกจากชื่อไฟล์
ใช้วิธีตัด string เหมือนเดิม แต่เนื่องจากส่วน .markdown อยู่ท้าย string
จะใช้วิธีนับ index แบบเดิมไม่ได้แล้ว เพราะชื่อไฟล์แต่ละไฟล์ยาวไม่เท่ากัน
ก็เลยให้มันตัด string หลังจากตัวจุด . ออกไปแทน
#!/bin/bash
markdownfiles=`ls *.markdown`
for file in $markdownfiles
do
filename=${file:11}
foldername=${filename%.*}
done
%.ตัดตัวอักษรตั้งแต่.เป็นต้นไป แล้ว return ส่วนที่เหลือ
5. เก็บส่วนที่เหลือไว้ สร้างโฟลเดอร์ใหม่
จาก variable ที่ได้จากขั้นตอนที่แล้ว เอาไปสร้างโฟลเดอร์ใหม่ด้วย mkdir.
#!/bin/bash
markdownfiles=`ls *.markdown`
for file in $markdownfiles
do
filename=${file:11}
foldername=${filename%.*}
mkdir $foldername
done
6. ย้ายไฟล์เดิมไปที่ใหม่
ใช้ mv
#!/bin/bash
markdownfiles=`ls *.markdown`
for file in $markdownfiles
do
filename=${file:11}
foldername=${filename%.*}
mkdir $foldername
mv $file $foldername/index.md
done
สุดท้ายก็ run script
$ ./rename.sh
content ทุกโพสต์ก็ถูกจัดระเบียบให้เหมือนกันแล้ว
ผมเชื่อว่าคนที่เก่ง unix command line / shell script สามารถทำให้ code 10 บรรทัดของผม อยู่ใน 1 บรรทัด (one-liner) ได้อย่างไม่ยากนัก หรือไม่ก็ใช้แอพ Automator ที่ติดมากับเครื่องอยู่แล้ว ก็น่าจะใช้ทำงานนี้ได้เหมือนกัน
เพราะการขี้เกียจทำงานซ้ำๆ เลยยอมเสียเวลาเสิช google นิดหน่อย หรือลองใช้เครื่องไม้เครื่องมือ เพื่อหาวิธีลดการทำงานที่ซ้ำๆ นั้นลง
แต่ก็ไม่ได้หมายความว่า ต้องเกิดจากความขี้เกียจเท่านั้นนะครับ
ตัวอย่างเช่น video เรื่อง Problem-Solving for Developers - A Beginner’s Guide ของช่อง Fireship.io เขียน script มาเพื่อจะได้ไม่ต้องกด merge pull requests กว่า 600 อันบน GitHub แบบ manual เพราะโจทย์มันใหญ่เกินกว่าจะทำแบบ manual ได้จริงๆ
แนะนำให้ไปชมวิธีการแก้โจทย์ของเขาครับ
Related posts