Hero Image
Advanced Shell Scripting Techniques: Automating Complex Tasks with Bash

Advanced Shell Scripting Techniques: Automating Complex Tasks with Bash Use Built-in Commands Built-in commands execute faster because they don’t require loading an external process. Minimize Subshells Subshells can be expensive in terms of performance. # Inefficient output=$(cat file.txt) # Efficient output=$(<file.txt) Use Arrays for Bulk Data When handling a large amount of data, arrays can be more efficient and easier to manage than multiple variables. # Inefficient item1="apple" item2="banana" item3="cherry" # Efficient items=("apple" "banana" "cherry") for item in "${items[@]}"; do echo "$item" done Enable Noclobber To prevent accidental overwriting of files. set -o noclobber Use Functions Functions allow you to encapsulate and reuse code, making scripts cleaner and reducing redundancy. Efficient File Operations When performing file operations, use efficient techniques to minimize resource usage. # Inefficient while read -r line; do echo "$line" done < file.txt # Efficient while IFS= read -r line; do echo "$line" done < file.txt Parallel Processing Tools like xargs and GNU parallel can be incredibly useful. Error Handling Robust error handling is critical for creating reliable and maintainable scripts. # Exit on Error: Using set -e ensures that your script exits immediately if any command fails, preventing cascading errors. set -e # Custom Error Messages: Implement custom error messages to provide more context when something goes wrong. command1 || { echo "command1 failed"; exit 1; } # Trap Signals: Use the `trap` command to catch and handle signals and errors gracefully. trap 'echo "Error occurred"; cleanup; exit 1' ERR function cleanup() { # Cleanup code } # Validate Inputs: Always validate user inputs and script arguments to prevent unexpected behavior. if [[ -z "$1" ]]; then echo "Usage: $0 <argument>" exit 1 fi # Logging: Implement logging to keep track of script execution and diagnose issues. logfile="script.log" exec > >(tee -i $logfile) exec 2>&1 echo "Script started" Automating Complex System Administration Tasks: Automated Backups System Monitoring User Management Automated Updates Network Configuration

Hero Image
寫 Web 也可以用 Makefile:好好管理你的環境流程

寫 Web 也可以用 Makefile:好好管理你的環境流程 How I stopped worrying and loved Makefiles 注意:Makefile 的縮排應使用 Tab,否則會出現語法問題。 Makefile 的主要本體:Target up: cp .env.example .env docker compose up -d workspace stop: docker compose stop zsh: docker compose exec workspace zsh 本例有三個 Target:up、stop、zsh。Makefile 預設將第一個 Target 視為 Goal(不能是點(dot)開頭的 Target),是專案的最主要流程,可以直接用 make 執行。以本例來說,執行 make 和 make up 是一樣的結果。 但其實剛剛複製檔案的例子不是常見的 Make 用法。Make 的強項是在自動判斷有沒有必要執行每個 Target 的流程。例如我們常常將機敏資料放在 .env 中,若 .env 已經存在,就不應該再複製 .env.example 覆寫過去了。這時候我們可以把 .env 做成一個 Target: up: .env docker compose up -d workspace .env: cp .env.example .env Target 名稱預設是被視為檔名的。Make 之所以稱為 make,就是想要「製作」出指定的 Target,當符合指定條件時(如檔案不存在)才會執行 Target 的內容。 以本例來說,我們執行 up Target 時,如果 .env 不存在,就會先執行 .env Target 以複製出 .env,接著才會啟動 workspace container。如果執行 up Target 時 .env 已經存在,就會略過 .env Target,直接啟動 workspace container。 同樣地,如果我們目錄中有「up」這個檔案, up Target 就不會被執行了。這時我們可以設定 Phony Target,告訴 Make 哪些 Target 不是檔案的名稱,而是單純流程的命名。寫法如下: .PHONY: up stop zsh 來點變數 Make 當然也支援變數(Variable),與常見的 Unix 環境變數慣例相同,我們習慣用 SCREAMING_SNAKE_CASE 表示法(全大寫和底線的表示法)。並且在使用時以 $() 包裹變數名稱。

Hero Image
How to Delete Files With Names That Contain Non-printable Characters

How to Delete Files With Names That Contain Non-printable Characters ls -l total 13 -rw-r--r-- 1 ZZ 197121 4 Nov 6 07:08 ' ' -rw-r--r-- 1 ZZ 197121 162 Apr 16 2022 '~$iscord.docx' -rw-r--r-- 1 ZZ 197121 6 Nov 6 06:03 ''$'\302\226' -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:01 ''$'\302\226''Λ---ω' -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:13 '␴?␴??␴??::␴?␴' -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:12 ␴__␴ -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:14 ␴␴␴␴␴␴␴␴␴␴␴␴␴␴␴␴␴ -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:18 '␴ω␴␴␣␦'$'\342\220\264' -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:16 ␣␣␣␣␣␣␣␣ -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:26 ␣ μ μ Ω Ω -rw-r--r-- 1 ZZ 197121 14 Nov 6 06:23 '␣ μ ␴'$'\342\220\264''Ξ' -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:27 -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:27 Using ANSI-C Quoting # Using ANSI-C Quoting rm ''$'\302\226' # We can also use the $ special character before enclosing the filename in single quotes rm $'\356\200\215' # pass an item's name to rm without using the ANSI-C quoting rm '\026\033' rm: cannot remove '\026\033': No such file or directory Using Inode Numbers ls -li total 11 ... 6517085 -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:18 '␴ω␴␴␣␦'$'\342\220\264' 7826050 -rw-r--r-- 1 ZZ 197121 3 Nov 9 04:23 ''$'\356\200\215\356\200\215\356\200\215' 4685554 -rw-r--r-- 1 ZZ 197121 4 Nov 6 06:27 we can delete the desired file by passing its inode number to the -inum switch of the find command

Hero Image
How to Make Output Overwrite the Same Line in a Terminal

How to Make Output Overwrite the Same Line in a Terminal Introduction to the Problem $ cat print_status.sh !/bin/bash echo "[INFO] Processing file: readme.txt" sleep 2 To simulate the file processing echo "[INFO] Processing file: veryPowerfulService.service" sleep 2 echo "[INFO] Processing file: log.txt" echo "DONE" $ ./print_status.sh [INFO] Processing file: readme.txt [INFO] Processing file: veryPowerfulService.service [INFO] Processing file: log.txt DONE The “Magic Code”: \033[0K\r -n option asks the echo command to stop outputting the trailing newline character -e option allows the echo command to interpret backslash escapes such as \n (newline) and \r (carriage return) \033 - It’s the escape sequence. In other words, it’s ESC. \033[ - Then this becomes “ESC [”, which is the control sequence introducer (CSI). \033[0k - So it’s “CSI 0 K”. Further, “CSI 0 K” erases the text from the cursor to the end of the line. \r - This is the carriage return. It brings the cursor to the beginning of the line. $ cat print_status.sh #!/bin/bash echo -ne "[INFO] Processing file: readme.txt\033[0K\r" sleep 2 echo -ne "[INFO] Processing file: veryPowerfulService.service\033[0K\r" sleep 2 echo -e "[INFO] Processing file: log.txt\033[0K\r" echo "DONE" !/bin/bash printf "[INFO] Processing file: readme.txt\033[0K\r" sleep 2 printf "[INFO] Processing file: veryPowerfulService.service\033[0K\r" sleep 2 printf "[INFO] Processing file: log.txt\033[0K\r\n" echo "DONE"