4 คะแนน โดย GN⁺ 2024-03-01 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เพื่อผู้ใช้ที่ต้องการอ่านบทความเว็บจากเทอร์มินัลโดยตรง James' Coffee Blog จึงให้บริการบทความบล็อกในรูปแบบ หน้าแมนนวลของ Linux ด้วย
  • แม้จะเป็น URL เดียวกัน แต่หากไคลเอนต์ส่ง Accept: text/roff ก็จะใช้ HTTP content negotiation เพื่อให้ได้รับ เอกสาร roff แทน HTML
  • ไฟล์ .man ของแต่ละบทความถูกสร้างจากเทมเพลตที่มีส่วน TITLE, AUTHOR, PUBLISHED, POST, URL
  • ในเนื้อหาใส่ ต้นฉบับ Markdown เพื่อให้อ่านง่ายกว่า HTML แต่ระยะห่างในหน้าแมนนวลอาจไม่เรียบร้อยเสมอไป
  • NGINX ตรวจจับคำขอ text/roff แล้วเขียน URL ใหม่เป็นไฟล์ .man ดังนั้นจึงสามารถบันทึกด้วย curl แล้วเปิดแบบ man./post.page ได้

อ่านบทความบล็อกด้วย man

  • หน้าแมนนวล ของ Linux เป็นวิธีพื้นฐานในการตรวจสอบวิธีใช้คำสั่งจากเทอร์มินัล โดยปกติเปิดได้ด้วย man <command>
  • ตัวอย่างเช่น สามารถดูแมนนวลของคำสั่ง tac ได้ดังนี้
man tac
  • James' Coffee Blog จัดทำโฟลว์ให้สามารถอ่านบทความบล็อกเว็บในลักษณะเดียวกัน โดยดาวน์โหลดเวอร์ชัน roff จาก URL ของบทความแล้วเปิดด้วย man
  • ตัวอย่างคำขอจริงมีดังนี้
curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/ > post.page && man ./post.page

เลือกรูปแบบด้วย HTTP content negotiation

  • แกนหลักของการทำงานคือ HTTP content negotiation ที่ไคลเอนต์ใช้แจ้งเซิร์ฟเวอร์ว่าต้องการรูปแบบการตอบกลับใด
  • เฮดเดอร์ Accept ใช้ส่งชนิดคอนเทนต์ที่ต้องการ
    • ตัวอย่างเช่น Accept: image/png หมายถึงขอให้ส่งไฟล์ PNG หากเป็นไปได้
    • สามารถระบุชนิดคอนเทนต์หลายแบบพร้อมลำดับความสำคัญได้ แต่ในกรณีนี้ใช้เพียงการขอรูปแบบเฉพาะ
  • เมื่อต้องการรับบทความบล็อกในรูปแบบหน้าแมนนวล ให้ส่งเฮดเดอร์ Accept: text/roff
  • เซิร์ฟเวอร์จะดูเฮดเดอร์นี้แล้วส่งคืน การตอบกลับแบบ text/roff ที่เปิดได้ใน man แทน HTML

วิธีสร้างไฟล์ .man

  • หน้าแมนนวลของ Linux เขียนด้วยไวยากรณ์ roff
  • เว็บไซต์ถูกปรับให้สร้างเวอร์ชันหน้า man สำหรับบทความบล็อกแต่ละรายการ
  • โครงสร้างเทมเพลตที่ใช้มีดังนี้
.TH jamesg.blog 1 "" "jamesg.blog"
.SH TITLE
...
.SH AUTHOR
James' Coffee Blog (https://jamesg.blog)
.SH PUBLISHED
...
.SH POST
...
.SH URL
...
  • เทมเพลตใช้ชื่อโดเมนเป็นเฮดเดอร์ และสร้าง 5 ส่วน
    • TITLE
    • AUTHOR
    • PUBLISHED
    • POST
    • URL
  • ในเนื้อหาใช้ ต้นฉบับ Markdown
    • ระยะห่างในหน้าแมนนวลอาจไม่พอดีเสมอไป
    • แต่ก็อ่านง่ายกว่า HTML และสูญเสียข้อมูลเรื่องการแบ่งหัวข้อกับย่อหน้าน้อยกว่าข้อความธรรมดา

รับด้วย curl แล้วเปิดด้วย man

  • สามารถขอเวอร์ชัน roff ของบทความบล็อกได้ด้วยคำสั่งต่อไปนี้
curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/ > post.page
  • ผลลัพธ์ที่บันทึกไว้สามารถเปิดเหมือนหน้าแมนนวลในเครื่องได้
man ./post.page
  • หากเบราว์เซอร์ทั่วไปขอ URL บทความเดียวกัน จะได้รับเวอร์ชัน HTML
  • ในทางกลับกัน คำสั่ง curl ข้างต้นขอ เวอร์ชัน text/roff สำหรับ URL เดียวกันอย่างชัดเจน

เขียนใหม่เป็นไฟล์ .man ใน NGINX

  • เซิร์ฟเวอร์จัดการคำขอ text/roff แยกต่างหากด้วยการตั้งค่า NGINX เพียงไม่กี่บรรทัด
  • ใน /etc/nginx/nginx.conf ประกาศตัวแปรที่ตั้งค่าแฟล็กเมื่อตรวจพบชนิดคอนเทนต์เฉพาะ
map $uri $redirect_suffix {
~^/(.*)/$ $1;
default "";
}
map $http_accept $redirect_location {
default "";
"~^text/roff" 1;
}
  • ใต้ /etc/nginx/sites-enabled ซึ่งเป็นไฟล์ตั้งค่าของไซต์ เพิ่มกฎสำหรับจัดการคำขอหน้า roff
server {
...
location / {
if ($redirect_location = 1) {
rewrite ^/(.*)/$ /$1.man last;
}
...
}
}
  • การตั้งค่านี้จะลบเครื่องหมายทับท้าย URL แล้วเติม .man เมื่อมีเฮดเดอร์ Accept: text/roff
  • ผลคือ NGINX จะอ่าน ไฟล์ .man ที่สอดคล้องกัน แทน index.html ของแต่ละบทความ
  • จึงเป็นการตั้งค่าที่ทำให้อ่านบทความบล็อกเดียวกันได้เป็น HTML ในเว็บเบราว์เซอร์ และเป็นหน้าแมนนวลของ Linux ในเทอร์มินัล

1 ความคิดเห็น

 
GN⁺ 2024-03-01
ความคิดเห็นบน Hacker News
  • ถ้าให้บริการ deb repository ในรูปแบบการสมัครรับข้อมูลบล็อกก็น่าจะเจ๋งดี
    แนว ๆ ใช้ apt update เพื่อดึงบทความทั้งหมดมา แล้วใช้ man your-blog เพื่อดูบทความล่าสุดและลิงก์ดัชนีของบทความทั้งหมด

    • ไอเดียนี้ยอดเยี่ยมก็จริง แต่ถ้ามันแพร่หลายขึ้น โอกาสในการ แพร่กระจายมัลแวร์ ที่แฝงอยู่ในวิธีนี้ก็ดูค่อนข้างชัดเจน
      คงรู้สึกกลัวที่จะสมัครรับ
    • มีตัวอย่างมาก่อนอยู่แล้ว Debian เคยให้การเข้าถึง Linux Gazette ซึ่งตอนนี้หายไปแล้ว และตอนนี้ก็ยังมี แพ็กเกจเชิงข้อมูล หลายอย่าง เช่น เอกสารแพ็กเกจ, manual page, info page, RFC, Linux HOWTO
      สิ่งเหล่านี้ดูในเครื่องได้ด้วยแพ็กเกจ dwww: “Read all on-line documentation with a WWW browser”
      https://packages.debian.org/bookworm/dwww
      Joerg Jaspert เคยเป็นผู้ดูแลแพ็กเกจ Linux Gazette: https://people.debian.org/~joerg/ (2002)
      ในบรรดาตัวอย่างที่เคยเห็นของการรวมการส่งมอบข้อมูลและเอกสารเข้ากับระบบปฏิบัติการ นี่เป็นหนึ่งในตัวอย่างที่ดีที่สุด และโดยเฉพาะอย่างยิ่งทำให้เอกสาร man/info มีประโยชน์กว่าอินเทอร์เฟซแบบเทอร์มินัลดั้งเดิม
      มีบล็อกเกี่ยวกับ Debian ชื่อ Debian Planet ด้วย แต่ดูเหมือนไม่เคยถูกจัดให้เป็นแพ็กเกจของ Debian เอง
      พูดตรง ๆ แล้ว RSS น่าจะเป็นตัวเลือกที่ดีกว่าสำหรับการสมัครรับบล็อก
    • กำลังทำอยู่ตอนนี้
      ที่ https://github.com/capjamesg/jamesg.blog.deb มีสิ่งที่ใช้สร้างไฟล์ deb ที่มีเฉพาะ man page ได้ด้วยคำสั่งด้านล่าง
      git clone [https://github.com/capjamesg/jamesg.blog.deb](<https://github.com/capjamesg/jamesg.blog.deb>;)
      cd jamesg.blog.deb
      dpkg-deb --build --root-owner-group jamesg.blog
      sudo dpkg -i jamesg.blog.deb
      จากนั้นคุณจะเห็นเอาต์พุตอย่าง Processing triggers for man-db (2.9.1-1) ... ซึ่งหมายความว่า manual page สำหรับ man jamesg.blog พร้อมใช้งานแล้ว
      ตอนนี้ยังมีแค่ placeholder คิดว่าน่าจะทำเสร็จพรุ่งนี้
      อาจกลายเป็นบทความบล็อกเร็ว ๆ นี้
  • สามารถ pipe เข้า man ได้โดยตรง ไม่ต้อง fork หรือเขียนไฟล์ชั่วคราว
    curl -sL -H "Accept: text/roff" [https://jamesg.blog/2024/02/28/programming-projects/](<https://jamesg.blog/2024/02/28/programming-projects/>;) | man -l -

    • ไม่ควรทำแบบนั้น เมื่อ 2 ชั่วโมงก่อน yrro ก็โพสต์อะไรคล้าย ๆ กัน และตอนนี้การถกเถียงเรื่อง pipe {curl,wget} เข้า command ก็เริ่มขึ้นอีกแล้ว
      ถ้าเป็นเพื่อนกัน เพื่อนจะไม่ปล่อยให้เพื่อน pipe stream เข้า command โดยตรง
      https://news.ycombinator.com/item?id=39554044
  • อ้างอิงไว้ว่า curl -sL -H "Accept: text/roff" [https://jamesg.blog/2024/02/28/programming-projects/](<https://jamesg.blog/2024/02/28/programming-projects/>;) | man -l /dev/stdin ใช้ได้ในสภาพแวดล้อมของผม
    ไม่จำเป็นต้องบันทึกไฟล์ roff ไว้ในเครื่อง

    • ดูเหมือนผู้เขียนต้นฉบับตั้งใจไม่ทำแบบนี้ การ pipe คำสั่งหรือเนื้อหาที่ได้จากอินเทอร์เน็ตเข้าไปในที่อย่าง bash โดยตรง มักถือเป็น แนวปฏิบัติที่ไม่ดี
      ส่วนตัวผมคิดว่าโอเค คนที่เข้าใจความหมายด้านความปลอดภัยก็น่าจะรู้วิธีแปลงแบบนี้อยู่แล้วแทบแน่นอน จึงไม่จำเป็นต้องบอกเป็นพิเศษ
      แต่ไม่เหมาะที่จะบอกมือใหม่ สักวันอาจโดนเล่นงานได้ พอฝีมือดีขึ้นก็คงรู้จักฟีเจอร์แบบนี้เอง และหวังว่าเมื่อถึงตอนนั้นจะได้เรียนรู้ผลที่ตามมาด้วย
      ไม่ใช่บทความที่ผมเขียน: https://www.seancassidy.me/dont-pipe-to-your-shell.html
    • น่าเสียดายที่คำสั่งนั้นใช้ไม่ได้บน macOS: /usr/bin/man: illegal option -- l
      ผมลองทำ one-liner ที่ใช้ pipe บน Mac แล้ว แต่เจอ error ตลอด
      implementation ของ man บน macOS ไม่มีแฟล็ก -l ตรวจดู manual page แล้ว
    • ถ้าใช้ bash สามารถลดตัวอักษรลงได้อีกเล็กน้อยด้วย process substitution แทน pipe
      man -l <(curl -sL -H "Accept: text/roff" https://jamesg.blog/2024/02/28/programming-projects/)
  • ถ้าพูดถึง URL ที่ทำอะไรสนุก ๆ ในเทอร์มินัล ก่อนหน้านี้เคยเห็นที่ textfiles.com
    เป็นรูปแบบที่แสดงภาพยนตร์แอนิเมชันสั้น ๆ ด้วยโค้ดเทอร์มินัล VT100 และทั้งหมดถูกเสิร์ฟจาก URI เดียว
    บนระบบสมัยใหม่สามารถตั้งการจำกัดความเร็วเพื่อดูได้
    curl --limit-rate 1000 [http://textfiles.com/sf/STARTREK/trek.vt](<http://textfiles.com/sf/STARTREK/trek.vt>;) && reset
    ใส่ reset ไว้เพราะเทอร์มินัลอาจพังได้
    URI แบบเทอร์มินัลอื่น ๆ เช่น curl cheat.sh/tar จะดึงตัวอย่างการใช้งานโปรแกรมหลัง / มาให้ และ curl wttr.in/berlin จะดึงข้อมูลสภาพอากาศที่จัดรูปแบบสำหรับเทอร์มินัลมาให้

    • ถ้าอยากทำ วิดีโอ ASCII เองด้วย telnet มีตัวที่ผมทำด้วย Go ไว้เมื่อหลายปีก่อน: https://github.com/bfontaine/RickASCIIRoll
      จริง ๆ แล้วค่อนข้างเรียบง่าย ส่วนที่ยากที่สุดคือการสร้างเฟรม
      ทำได้ด้วย ffmpeg+img2txt.py: https://github.com/bfontaine/RickASCIIRoll/tree/master/movie...
    • เมื่อหลายปีก่อนเคยทำตัวดู ANSI art ที่มี การจำลองความเร็วโมเด็ม
      มีมิเรอร์เก่าของ https://16colo.rs/ อยู่ จึงดู ANSI art ส่วนใหญ่ที่เผยแพร่มาจนถึงตอนนี้ได้
      ตัวอย่าง: curl ansi.hrtk.in/ungenannt_1453.ans
    • เจ๋งมากจริง ๆ แต่ก็ทำให้เทอร์มินัลพังสนิทเหมือนกัน สนุกดี
    • มี Star Wars ที่ดูผ่าน telnet ด้วย
      https://itsfoss.com/star-wars-linux/
    • ใช้ tritty เพื่อจำลองความเร็วรับส่ง 1200/9600 BPS ได้
  • ตอนนี้สิ่งที่ต้องมีก็แค่ตัวแปลง Markdown เป็น roff เท่านั้น พอลองหาดูก็มีอยู่แล้ว
    https://github.com/postmodern/kramdown-man
    https://rtomayko.github.io/ronn/ronn.1.html
    https://kristaps.bsd.lv/lowdown/

    • สำหรับงานแบบนี้ pandoc เหมาะดี รองรับรูปแบบมาร์กอัปส่วนใหญ่ที่ผมต้องใช้
      [0]: https://pandoc.org/
    • md2groff มีอยู่ในชุมชนสาย suckless/2f30/cat-v มานานแล้ว
      https://codeberg.org/nereusx/md2roff
  • มีแพ็กเกจ Emacs ที่ติดตั้ง SICP ของ Abelson และ Sussman ลงในไดเรกทอรี Info ให้
    แค่พิมพ์ M-x package-install sicp RET ก็พอ
    พอเห็นแบบนี้ก็คิดได้ว่า อาจติดตั้งทั้งชั้นหนังสือคลังบทความบล็อกด้วย feed reader ที่แก้ไขแล้วได้เหมือนกัน
    ถ้าอ่าน Info ใน Emacs ก็ใช้บุ๊กมาร์กได้ด้วย

    • ติดตั้ง chicken-scheme ด้วยก็ได้ จากนั้นรันเป็น root
      chicken-install srfi-203
      chicken-install srtfi216
      ~/.csirc สำหรับ SICP เป็นดังนี้
      (import scheme)
      (import (srfi 203))
      (import (srfi 216))
      (define (inc x) (+ x 1))
      (define (dec x) (- x 1))
      จากนั้นก็ใช้ user geiser กับ geiser สำหรับ chicken ตามปกติได้เลย
    • สำหรับข้อมูลอ้างอิง SICP เป็นหนังสือของ Abelson และ Sussman
  • ถ้าค้นในอินเทอร์เน็ตก็คงรู้คำตอบได้ แต่ขอถามใน HN
    สมัยมัธยม ผมจำได้ว่าบน HP-UX มีคนแสดงให้ดูว่ากดคีย์ผสมบางอย่างเพื่อกระโดดไปยังคำที่ขีดเส้นใต้ หรือก็คือการอ้างอิง section แต่ยังไงก็นึกไม่ออกว่าเป็นคีย์อะไร
    ตรวจ man(1) กับ man(7) แล้วก็ไม่เจอ อาจเป็นความทรงจำปลอมก็ได้

    • ถ้านั่นคือ man ต้องคิดไว้ว่า man ohman โดยพื้นฐานแล้วคือ nroff -man /usr/share/man/man1/ohman.1 | $PAGER
      กล่าวคือไม่ได้โต้ตอบกับ man หรือ nroff แต่โต้ตอบกับ pager
      ทุกวันนี้ less พบบ่อยที่สุด และ more ก็มีโอกาสสูงที่จริง ๆ จะเป็น less แต่สมัยก่อนมีอย่างอื่นด้วย และ HPUX อาจใช้ของอย่าง pg
      pg เป็นสาย AT&T, more เป็นสาย BSD, ส่วน less เป็นสาย GNU
      ทั้งสามตัวเริ่มค้นหาด้วย regex ด้วย / ดังนั้นหาได้ไม่ว่าจะมีขีดเส้นใต้หรือไม่
      less รองรับไฟล์แท็กด้วย จึงกด t เพื่อกระโดดไปแท็กถัดไปได้
    • ไม่ค่อยรู้เรื่องฟีเจอร์ของตัวดู man แยกต่างหาก แต่คุณอาจนึกถึง dthelpview ซึ่งเป็น ตัวดูวิธีใช้ของ CDE ก็ได้ ตัวนี้อาจแสดง man page ได้
    • ฟังดูเหมือน texinfo ที่เปิดด้วยคำสั่ง info
      น่าขันที่เอกสาร groff ดั้งเดิมจำนวนไม่น้อยเขียนด้วย texinfo: https://lists.gnu.org/archive/html/groff/2005-10/msg00107.ht...
  • ไม่รู้เหมือนกันว่าทำไมรายละเอียดเล็กน้อยนี้ถึงไปกระตุ้นสัญชาตญาณจับผิดของผม อาจเป็นเพราะมีใครบางคนบนอินเทอร์เน็ตพูดผิดไปนิดหน่อย
    อาจเป็นเพราะมันเน้น Linux โดยไม่จำเป็นมาตั้งแต่แรก หรือเพราะผมคาดหวังอะไรอย่างอื่น แต่สุดท้ายมันเป็นแค่เดโมสั้น ๆ เรื่อง content negotiation ของ NGINX
    ยังไงก็ตาม มีจุดเล็ก ๆ น้อย ๆ ที่ไม่จำเป็นแต่ผมก็อยากพูดถึง
    ถ้าพูดอย่างเคร่งครัด มันไม่ได้ส่งคืน roff จริง ๆ สิ่งอย่าง .TH ไม่ใช่ roff เอง แต่เป็นส่วนหนึ่งของแพ็กเกจแมโครสำหรับเขียนหน้า man
    ผมผิดหวังที่ไม่มีการแปลง Markdown-to-roff นึกว่านั่นจะเป็นส่วนที่น่าสนใจของบทความนี้ และอย่างน้อยก็น่าจะใช้เครื่องมือที่มีอยู่แล้วสักตัวได้
    ในทำนองเดียวกัน ด้วยเหตุนี้การจัดรูปแบบข้อความจึงไม่ได้ถูกต้องจริง ๆ อินพุต roff ตั้งใจให้หนึ่งประโยคอยู่หนึ่งบรรทัด เพื่อแยก . ท้ายประโยคออกจาก . ที่ใช้เพื่อจุดประสงค์อื่น
    อีกอย่าง ทุกบรรทัดที่ขึ้นต้นด้วย . อาจถูกตีความเป็นคำสั่งและก่อปัญหาได้
    หรือไม่ก็ผมอาจเป็นแค่ตาแก่ขี้หงุดหงิดก็ได้

    • ขอบคุณที่แชร์เรื่องนี้ ผมไม่รู้แน่ชัดว่าโครงสร้างความสัมพันธ์ระหว่าง roff กับ man เป็นอย่างไร และพยายามแก้บทความนี้หลายรอบให้ตรง
      พอมีเครื่องมืออื่นอย่าง groff, nroff ด้วย ก็ยิ่งสับสน
      แค่บทความที่อธิบายว่า “roff/man page/nroff/รูปแบบอื่น ๆ คืออะไรและใช้อย่างไร” ก็เพียงพอจะเป็นบล็อกโพสต์หนึ่งบทความได้แล้ว
      ถ้ามีคำอธิบายสั้น ๆ ชัด ๆ ผมก็คงดีใจ และน่าจะเป็นประโยชน์กับคนอื่นด้วย
      Markdown-to-roff ผมมองไว้เป็น v2 ตอนเริ่มคิดว่าจะทำ parser เอง มีคนบอกผมเรื่อง https://github.com/sunaku/md2man และดูเหมือนจะแก้ปัญหานี้ได้
      ต้องไปดูว่าจะผสานมันเข้ากับไซต์ Python ของผมที่รันบน GitHub Pages ได้อย่างไร คงต้องปรับแต่งอีกนิดหน่อย
    • ผมก็ค่อนข้างแปลกใจเหมือนกันที่ไม่มีการแปลง Markdown-to-roff
      Pandoc แปลง Markdown เป็น roff สำหรับ man page ได้ง่ายมาก
      ถ้าเอาไปใส่ในเทมเพลตที่กำหนดไว้ ก็น่าจะดูเหมือนหน้า man จริง ๆ มากขึ้น
  • media type ที่ถูกต้องตาม RFC 4263 คือ text/troff: https://www.rfc-editor.org/rfc/rfc4263.html

  • ไอเดียเจ๋งดี ตอนนี้ก็แค่เริ่มจับเวลาว่า “ให้บริการบทความบล็อกของผมในรูปแบบ DOOM WAD ที่เล่นได้” จะออกมาเมื่อไหร่

    • เพิ่มเข้าไปในรายการงานเจ๋ง ๆ ไม่กี่อย่างที่ AI ช่วยได้จริงได้เลย