- Giới thiệu những script shell được dùng nhiều nhất trong số nhiều script khác nhau đã viết khi duy trì dotfiles hơn 10 năm
- Được chia thành các nhóm clipboard · quản lý tệp · Internet · xử lý văn bản · trình khởi chạy REPL · ngày/giờ · AV · tiến trình · tham chiếu nhanh · hệ thống · linh tinh, và mỗi script được trình bày theo dạng wrapper ngắn gọn cùng ví dụ thực chiến
- Phần lớn script hoạt động trên macOS và Linux, với triết lý cốt lõi là “làm phẳng những phiền toái lặt vặt của các công cụ sẵn có”
- Tích hợp các tiện ích tiêu chuẩn như
pbcopy/xclip, python3 -m http.server, yt-dlp, ffmpeg, mpv
- Những script được dùng nhiều nhất gồm
copy/pasta/pastas/cpwd, mkcd/tempe/trash/mksh, serveit/getsong/getpod/getsubs, scratch/straightquote/markdownquote, timer/boop/tunes v.v.
Giới thiệu những script tôi dùng thường xuyên nhất khi duy trì dotfiles
- Trong số nhiều script shell đã tạo ra suốt hơn 10 năm quản lý dotfiles cá nhân, bài viết này sắp xếp những script được dùng thường xuyên theo từng lĩnh vực
- Mỗi script đều đi kèm mục đích, tần suất sử dụng và ví dụ tiêu biểu, giúp tăng khả năng áp dụng ngay lập tức
- Mục tiêu chung là rút ngắn công việc lặp lại, trừu tượng hóa giữa các nền tảng, và cải thiện độ an toàn · khả năng đọc
Script liên quan đến clipboard
copy và pasta: wrapper bọc quanh trình quản lý clipboard của hệ thống, dựa trên pbcopy của macOS hoặc xclip của Linux
copy: sao chép đầu ra vào clipboard
pasta: lấy văn bản từ clipboard và in ra
- Ví dụ:
run_some_command | copy, pasta > file.txt, vim "$(pasta)", pasta | base64 --decode
pastas: công cụ in ra nội dung mới theo thời gian thực mỗi khi trạng thái clipboard thay đổi
- Hữu ích khi lưu tất cả liên kết đã sao chép vào một tệp, hoặc tải hàng loạt nhiều liên kết
- Ví dụ:
pastas > everything_i_copied.txt, pastas | wget -i -
cpwd: sao chép đường dẫn thư mục hiện tại vào clipboard
- Tiện khi di chuyển thư mục giữa nhiều tab terminal
Script quản lý tệp
mkcd foo: tạo thư mục và di chuyển vào ngay lập tức (rút gọn của mkdir foo && cd foo)
tempe: chuyển vào thư mục tạm (cd "$(mktemp -d)"), không cần dọn dẹp khi làm việc tạm trong môi trường sandbox
trash: chuyển tệp vào thùng rác (hỗ trợ macOS/Linux), giúp tránh sai sót so với rm đơn thuần
mksh: tạo tệp shell script mới, đặt quyền thực thi và mở ngay bằng trình soạn thảo
Script liên quan đến Internet
serveit: chạy máy chủ tệp tĩnh từ thư mục cục bộ (mặc định cổng 8000, có phương án thay thế nếu chưa cài Python)
getsong dùng yt-dlp để tải âm thanh với chất lượng tốt nhất
getpod là wrapper nhận video dưới dạng audio dành cho podcast
getsubs trích xuất phụ đề tiếng Anh với logic ưu tiên phụ đề chính thức và fallback sang phụ đề tự động. Phù hợp cho pipeline tóm tắt và mục đích sao lưu
wifi off/on/toggle: điều khiển Wi‑Fi hệ thống, dùng khi xử lý sự cố mạng
url: phân tích chuỗi URL để tách và trích xuất giao thức, hostname, đường dẫn, truy vấn, hash v.v.
Script xử lý văn bản
line 10: in ra dòng cụ thể từ stdin (tương tự head, tail)
scratch: dùng để nhanh chóng mở một buffer văn bản tạm trong Vim như $EDITOR $(mktemp), phù hợp cho ghi chú một lần hoặc các tác vụ chuyển đổi nhỏ
straightquote: chuyển dấu ngoặc kép/thể hiện trích dẫn kiểu thông minh thành dấu ngoặc thẳng thông thường, tránh lỗi dấu ngoặc trong code và giảm kích thước tệp
markdownquote: thêm > vào đầu mỗi dòng để tạo blockquote Markdown
length: trả về độ dài của chuỗi đầu vào (có thể thay bằng wc -c)
jsonformat: in dữ liệu JSON theo dạng đẹp
uppered/lowered: chuyển chuỗi sang chữ hoa/chữ thường
nato bar: chuyển chuỗi đầu vào sang bảng mã chữ cái NATO (Bravo Alfa Romeo v.v.)
u+ 2025: tra tên và ký hiệu của ký tự Unicode
snippets foo: gọi ra cụm viết tắt cụ thể từ bộ snippet cá nhân
snippet arrow là mũi tên →, snippet recruiter là các mẫu tin nhắn như “not interested”
Liên quan đến trình khởi chạy REPL
- Lấy cảm hứng từ
irb của Ruby để chạy nhanh REPL của nhiều ngôn ngữ khác nhau:
iclj: Clojure
ijs: Deno (nếu không có thì dùng Node)
iphp: PHP
ipy: Python
isql: SQLite (chế độ in-memory trong Bash)
Script ngày và giờ
hoy: in ngày hiện tại theo định dạng ISO (ví dụ: 2020-04-20), dùng làm tiền tố cho tên tệp v.v.
timer 10m: bộ hẹn giờ (10 phút v.v.), khi hoàn tất sẽ phát âm thanh và gửi thông báo của HĐH
rn: dùng date và cal để in thời gian hiện tại và lịch tháng theo cách dễ đọc
Xử lý âm thanh, video, hình ảnh
ocr: trích xuất văn bản từ tệp hình ảnh trên macOS (dự kiến mở rộng thêm)
boop: thông báo bằng âm thanh tùy theo lệnh trước đó thành công/thất bại (hữu ích trực quan sau khi chạy test v.v.)
sfx: phát một tệp hiệu ứng âm thanh cụ thể (.ogg), liên kết với boop, timer
tunes: phát tệp âm thanh bằng mpv (hỗ trợ shuffle)
pix: xem ảnh bằng mpv
radio: trình khởi chạy nhanh các đài radio Internet ưa thích
speak: loại bỏ Markdown khỏi văn bản đọc từ stdin rồi chuyển thành giọng nói (TTS)
shrinkvid: nén tệp video bằng ffmpeg
removeexif: xóa dữ liệu EXIF khỏi JPEG, dự kiến hỗ trợ thêm nhiều định dạng sau này
tuivid: xem video ngay trong terminal, ít dùng thực tế nhưng là một tính năng độc đáo
Quản lý tiến trình
each: thay thế cho xargs, find ... -exec, giúp thực thi các lệnh phức tạp dễ dàng hơn
running foo: tìm các tiến trình đang chạy theo từ khóa chỉ định (PID, lệnh v.v.) rồi in ra theo dạng dễ đọc
murder: wrapper cho kill, tuần tự thoát dần từ tín hiệu nhẹ đến mạnh để cưỡng bức kết thúc. Giúp tránh sai sót khi yêu cầu chương trình dừng
waitfor $PID: chờ cho đến khi PID chỉ định kết thúc, duy trì trạng thái thức trong lúc chờ
bb my_command: chạy lệnh ở chế độ background thực sự, phù hợp để chạy daemon v.v.
prettypath: in $PATH xuống từng dòng để dễ nhìn toàn cảnh hơn (hữu ích khi debug)
tryna my_command/trynafail my_command: lặp lại cho đến khi lệnh thành công (run until success), hoặc cho đến khi thất bại (run until fail), có thể ứng dụng cho mạng và nhiều tác vụ tự động hóa khác
Công cụ tham chiếu nhanh
emoji: tìm kiếm và in emoji theo từ khóa
httpstatus: in danh sách toàn bộ mã trạng thái HTTP, xem mô tả của từng mã cụ thể
alphabet: in toàn bộ bảng chữ cái tiếng Anh viết thường và viết hoa (tần suất sử dụng cao hơn tưởng tượng)
Quản lý hệ thống
theme 0/theme 1: chuyển theme toàn hệ thống (dark/light), liên kết với Vim, Tmux v.v.
sleepybear: đưa hệ thống vào chế độ ngủ (macOS, Linux)
ds-destroy: xóa đệ quy các tệp .DS_Store, hữu ích khi dọn dẹp thư mục của người dùng macOS
Khác
catbin foo: xem trực tiếp mã nguồn của tệp trong PATH
notify: gửi thông báo ở cấp hệ điều hành, tiện để báo ngay khi tác vụ dài hoàn tất
uuid: tạo UUID phiên bản 4
Kết luận
- Những script được giới thiệu trong bài là các công cụ mà tác giả thực sự dùng thường xuyên
- Các script lệnh tắt tự viết rất hiệu quả trong tối ưu hiệu suất công việc, tránh sai sót, nâng cao năng suất
- Bạn cũng nên thử tự tạo và sử dụng các script tự động hóa của riêng mình
2 bình luận
Ý kiến trên Hacker News
Lệnh
trash a.txt b.pngsẽ chuyển các tệpa.txtvàb.pngvào thùng rác, hỗ trợ trên Mac và Linux. Cách tôi từng làm trước đây xử lý tuần tự từng tệp, nên sẽ nghe tiếng xóa cho mỗi tệp và chỉ có thể khôi phục tệp cuối cùng bằng ⌘Z trong Finder. Có thể cải tiến thêm, nhưng thực ra dùng lệnhtrashchính thức được tích hợp sẵn trên macOS sẽ tiện hơn. Vì không dùng Finder nên không có âm thanh hay khôi phục bằng ⌘Z, nhưng nhanh hơn và vẫn hỗ trợ tính năng “Put Back”. Ngoài ra, để pretty-print JSON thì dùng jq thay vì node sẽ giải quyết được bằng đoạn mã ngắn hơn nhiều, và macOS gần đây đã cài sẵn jq. Tương tự, để in UUID thì nếu cần v4 UUID, dùng uuidgen là lựa chọn hợp lý (xem man page)Nhiều khi dùng chức năng tích hợp sẵn còn tốt hơn script tự viết. Ví dụ, trong vim thay vì dùng markdownquote, chỉ cần chọn cột đầu tiên bằng ctrl-v rồi nhấn "i> " và escape là xong. Ngắn hơn và hiệu quả hơn. Tôi cũng thắc mắc vì sao u+ 2025 lại trả về ñ, trong khi giá trị Unicode thực tế là U+00F1. Và catbin foo cũng tương đương với cat "$(which foo)". Nếu dùng zsh thì cat =foo còn ngắn và mạnh hơn. Trong zsh, sau dấu = có thể tự động hoàn thành nên an toàn để dùng cả với lệnh dài. Tôi hay dùng như file =firefox, vim =myscript.sh
Tôi đoán là tác giả không biết đến uuidgen. Điều tôi thích ở việc chia sẻ những kiến thức hay cấu hình kiểu này là nó luôn làm lộ ra những điểm mù của mình, nên việc chia sẻ rất quan trọng
Python cũng có thể pretty-print JSON theo mặc định
Cảm ơn vì thông tin về
trash. Trước giờ tôi vẫn dùng AppleScript kiểu "tell app "Finder" to move {%s} to trash" để chuyển nhiều tệp vào thùng rácNgoài rm và trash, tôi cũng đề xuất rip như một lựa chọn khác liên kết dự án rip
Vòng đời của một lập trình viên thật thú vị. Lúc đầu chỉ dùng môi trường shell thuần túy, đến năm thứ 1–2 thì viết hàng trăm dòng script và bash alias. Giờ đã 15 năm trong nghề, tôi lại cố dùng shell mặc định nhiều nhất có thể, không dùng alias, và xử lý phần phức tạp bằng Python hoặc Go
Xu hướng này có lẽ không hẳn là một trạng thái giác ngộ gì, mà chỉ là lười thôi (tôi cũng y như vậy nên mới nói thế). Nhờ những đồng nghiệp thích đào sâu môi trường tùy biến mà tôi thường xuyên học được công cụ mới, và gần đây cũng đã thêm atuin, fzf vào Linux của mình
Tôi ghi alias và function vào dotfile để dùng như cách ghi nhớ/lưu lại các lệnh hay dùng. Bộ công cụ hay dùng được cập nhật liên tục, và cũng dễ chuyển sang workstation mới
Hồi chỉ có một máy nix, tôi rất muốn tùy biến nhiều thứ. Giờ dùng nhiều máy cùng lúc nên tôi chỉ cài các gói cần thiết để đồng bộ môi trường
Những thứ viết bằng Python tôi vẫn gọi là script. Tôi không nghĩ thuật ngữ script chỉ giới hạn ở shell script
Gần đây làm việc với các kỹ sư trẻ, nhìn họ dùng đủ loại dotfiles lại thấy “ngày xưa mình cũng từng như thế, và cũng thấy phiền thật”. Giờ tôi chọn lọc công cụ để dùng, tùy biến linh hoạt theo nhu cầu, và cũng tôn trọng phong cách của người khác
Tôi rất thích tìm thấy những bài đăng mẹo thực chiến kiểu này trên HN. Tôi tò mò người khác thực sự làm việc như thế nào và mình có thể học rồi áp dụng điều gì. Ban đầu có thể nghĩ “chắc không cần cho mình đâu”, nhưng khi một tác vụ trở nên dễ hơn thì chính tác vụ đó lại tạo ra workflow mới. Vì thế tôi thường cứ thử trước rồi giữ lại cái hợp. Tôi cũng thích phong cách của bài gốc — việc ghi kèm tần suất sử dụng thực sự rất thực tế. Với các việc đơn giản, tôi thường mở devtools trong trình duyệt và giải quyết bằng JavaScript. (Ví dụ như chuyển chuỗi sang chữ thường)
Sẽ rất thú vị nếu làm một phân tích cost-benefit thực tế, tính cả thời gian theo cách của tác giả lẫn cách của tôi, cùng chi phí tạo script/ghi nhớ/tham chiếu/migration
Hình cheat sheet phím tắt Bash này rất hữu ích
Thay vì script line, dùng sed để in dòng cụ thể còn đơn giản hơn
Có thể in dòng thứ hai. Muốn in nhiều dòng thì
cũng làm được, nên tiện hơn script line
Tôi có vài script đơn giản hay dùng. Ví dụ:
Tôi đặt script cá nhân với tiền tố , (dấu phẩy) để chuyển nhanh. Tôi thấy việc định kỳ thống kê các script riêng của mình trong history và dọn bỏ những cái không còn dùng nữa là rất đáng làm
Tôi vẫn chưa khái quát hóa được, nhưng script
unmvđang giúp tôi làm việc khá tiệnCó nhiều mẹo hay, nhưng nhìn chung tôi học và dùng các utility chuẩn (sed, awk, grep, xargs, v.v.). Lý do là tôi thường phải làm việc qua lại giữa nhiều hệ thống, mà script và alias cá nhân của tôi hầu hết không được cài ở đó. Với utility chuẩn thì gần như làm được mọi việc
Tôi chia sẻ script giải nén yêu thích nhất của mình
Tôi cũng muốn làm một counterpart ngược lại để nén
Tôi dùng dtrx, nó tự động giải nén vào trong thư mục nên rất tiện
Tôi thấy aunpack tiện hơn
Gọn gàng thật
Nếu thêm cả inotify và systemd user service thì có thể tiến hóa thêm một bậc nữa. Cũng đã có phiên bản tồn tại dưới dạng package rồi. Tự làm lấy thì hơi giống tái phát minh bánh xe
Tôi có hai function luôn dùng để encode hoặc cắt mp4. Nhờ các flag này mà mức độ tương thích được tối đa hóa cho nhiều môi trường như WhatsApp, Discord trên di động, v.v.
fftime cắt rất nhanh mà không cần re-encode bản gốc, nhưng tùy video có thể gặp chút vấn đề (ví dụ không phát được). Nếu muốn re-encode thì bỏ
-c copyđiMỗi khi tạo và test alias hay function, tôi thích áp dụng ngay
~/.zshrc, nên dùng alias như bên dưới cho tiệnVà trên Mac, tôi dùng function sau để grep trong tệp docx
Ngoài ra, để ẩn danh clipboard trên Mac trước khi dán vào ChatGPT, Slack nội bộ hay các kênh công khai khác cho mục đích debug, tôi dùng function dưới đây. Khi chạy function, clipboard đã được chuyển đổi mới cũng sẽ được in ra stdout, nên có thể kiểm tra xem còn sót gì không
Điều này cũng khiến tôi nhớ tới bài viết từng được đăng trên GeekNews: Ask GN: Bạn có shell snippet tự viết nào thường dùng không?