1 điểm bởi GN⁺ 2 giờ trước | 1 bình luận | Chia sẻ qua WhatsApp
  • : trong shell là lệnh rỗng (null command) chỉ đánh giá đối số rồi bỏ qua, và khi kết hợp với mở rộng tham số có thể xử lý ngắn gọn việc kiểm tra đối số bắt buộc và thiết lập giá trị mặc định
  • : "${1:?missing argument, aborting!}" sẽ in thông báo chẩn đoán ra stderr và thoát với trạng thái khác 0 nếu $1 không có hoặc rỗng
  • Khi truyền ${VAR:=default} làm đối số cho :, phần mở rộng vẫn được thực thi nhưng chuỗi kết quả bị bỏ đi, vì vậy có thể chỉ thiết lập giá trị mặc định mà không thực thi kết quả mở rộng như một lệnh
  • Có thể dùng : để làm rỗng tệp và kiểm tra khả năng truy cập bằng chuyển hướng, làm lệnh rỗng cho trap, kiểm tra biến trong môi trường set -u, và cả trong các nhánh điều kiện để trống
  • : "${VAR:=default}" chỉ cần viết tên biến một lần nên giảm khả năng gõ nhầm, và trong while: nó trở thành điều kiện luôn thành công để biểu đạt vòng lặp vô hạn

Lệnh rỗng và mở rộng tham số

  • : là lệnh nội bộ lệnh rỗng: đánh giá các đối số rồi bỏ kết quả đi
    • Nó có lịch sử ngược về tận Thompson shell năm 1971, khi đó còn được dùng như nhãn và là ký hiệu chú thích đầu tiên của Unix
  • Thay vì một câu lệnh điều kiện bốn dòng, có thể kiểm tra đối số bắt buộc chỉ bằng một dòng sau
: "${1:?missing argument, aborting!}"
echo "Hello $1!"
  • Cú pháp mở rộng tham số ${name:?diagnostic} sẽ kiểm tra xem $name có chưa được thiết lập hoặc đang rỗng hay không
    • Nếu không có giá trị, nó sẽ in diagnostic ra stderr và thoát shell với trạng thái khác 0
    • Nếu có giá trị, nó cho ra kết quả giống như $name
  • Nếu chạy ${HELLO:=123} mà không có lệnh rỗng, kết quả mở rộng 123 sẽ bị coi là một lệnh và gây ra lỗi command not found
    • : ${HELLO:=123} sẽ đánh giá phần mở rộng để thiết lập HELLO=123, đồng thời bỏ đi kết quả đó
  • : "${DATA_DIR:=/var/data}" khác với DATA_DIR="${DATA_DIR:-/var/data}" ở chỗ chỉ cần viết tên biến một lần, nên giảm khả năng gõ nhầm như DATA_DRI

Cách tận dụng :

  • Thiết lập giá trị mặc định

    • Thiết lập giá trị mặc định cho biến trong khi bỏ đi kết quả mở rộng thay vì thực thi nó
: "${DATA_DIR:=/var/data}"
: "${RETRIES:=3}"
  • Làm rỗng tệp và kiểm tra truy cập

    • Khi kết hợp với chuyển hướng, nó có thể làm rỗng một hoặc nhiều tệp
: > error.log
: > error.log > access.log
  • Cũng có thể dùng subshell và chuyển hướng để kiểm tra khả năng đọc/ghi của tệp
( : < dataset.json ) && echo YES
( : >> result.json ) && echo YES
  • Những vị trí cần một lệnh rỗng

    • Có thể dùng khi cú pháp bắt buộc phải có lệnh, như với trap, nhưng thực tế lại không muốn làm gì
trap : INT
sleep 60
  • Cũng có thể đặt vào các nhánh cần để trống trong câu lệnh điều kiện
if some-command; then
    :
else
    echo "command failed"
fi
  • Kiểm tra nhiều biến

    • Khi set -u đang bật, có thể kiểm tra một lượt xem nhiều biến đã được thiết lập hay chưa
set -u
: "$DEPLOY_ENV" "$HOST"
  • Vòng lặp vô hạn

    • : luôn là điều kiện thành công, có thể viết vòng lặp vô hạn một cách ngắn gọn
while :; do
  echo "I love colons"
  sleep 1
done

1 bình luận

 
Các bình luận trên Lobste.rs
  • Nếu cấu hình prompt như sau, thì ngay cả khi sao chép và dán cả một dòng, phần prompt sẽ bị bỏ qua và chỉ lệnh được thực thi
    : hayalci@tassadar ~/src/dool ; jj rebase -s dxw -d mrn
    • Lấy cảm hứng từ Plan 9, cũng dùng tùy chọn autocd của shell và định dạng sau
      ~/directoryname; <command>
      Mỗi lần sao chép dòng lệnh của shell, nó sẽ tiếp tục cd về thư mục nơi lệnh ban đầu được chạy
    • Trong zsh, thiết lập để khi dán khoảng trắng không xuống dòng vô hình thì nội dung bên trái bị xóa
      nbsp=$'\u00A0'  
      PS1="...$nbsp"  
      bindkey -s $nbsp '^u'  
      
  • Trong Makefile, thường dùng dấu hai chấm để in ra đẹp hơn
    out/%.o: src/%.c  
        @echo CC $@  
        @$(CC) -c -o $@ $<  
    
    Cách này có thể khiến make chạy nhiều tiến trình echo đồng thời và cùng ghi ra một stream, gây can nhiễu lẫn nhau. Nếu đổi như sau, không phải tiến trình con mà chính tiến trình make sẽ in ra
    out/%.o: src/%.c  
        : CC $@  
        @$(CC) -c -o $@ $<  
    
  • Từng thấy kỹ thuật này trong shell script, nhưng khó tìm được tài liệu hữu ích bằng man : hay whatis :
    Nó giống lệnh true, nhưng khác ở chỗ không phản hồi đặc biệt với --help, --version, v.v., và cũng ít ký tự hơn
    • Lệnh tích hợp sẵn của Bash nên tra bằng help thay vì man
      $ help :  
      :: :  
          Null command.
      
          No effect; the command does nothing.
      
          Exit Status:  
          Always succeeds.  
      
    • Trong Fish, : đúng nghĩa là bí danh của true
  • Việc mở rộng tham số vẫn xảy ra dù không có dấu hai chấm, nên thắc mắc vì sao vẫn cần lệnh null
    • Mở rộng tham số vẫn diễn ra, nhưng nếu không có cú pháp tiêu thụ kết quả như lệnh null, shell sẽ coi chuỗi đã mở rộng là lệnh cần thực thi. Nội dung này cũng đã được thêm vào FAQ
      % ${HELLO:=123}  
      zsh: command not found: 123  
      
      % : ${HELLO:=123}  
      % echo $HELLO  
      123  
      
    • Kết quả của chuỗi được nội suy sẽ được diễn giải thành lệnh cần thực thi
      #!/bin/sh  
      "${1:?missing argument, aborting!}"  
      
      $ sh foo.sh sh  
      sh-5.3$  
      
  • Khi đang nhập một lệnh nhưng muốn chạy lại sau, thêm dấu hai chấm ở đầu dòng để lưu vào lịch sử. Sau đó tìm dòng đó trong lịch sử và chỉ cần xóa ký tự đầu tiên là có thể thực sự chạy nó
    Tuy nhiên chưa từng nghĩ đến việc tận dụng nó cho tác dụng phụ phát sinh khi đánh giá các đối số
    • Cũng có thể thêm # thay cho : để lưu dưới dạng chú thích. Nếu đó là nội dung sẽ chạy sau, lợi thế là các biểu thức bên trong không bị đánh giá trước
    • Trong zsh, có thể dùng Meta-q hoặc Alt-q để tạm đẩy dòng hiện tại sang một bên, chạy lệnh khác, rồi khi xong thì đưa dòng ban đầu trở lại bộ đệm dòng lệnh
      https://nathangrigg.com/2014/04/zsh-push-line-or-edit/
  • Trên macOS vẫn đang dùng Bash 3 và gặp lỗi sau
    -bash: !}": event not found
    • Thắc mắc liệu bỏ việc dùng "!" thì có hoạt động không
  • Đoạn mã sau trong Con-colon-sion có khả năng làm người đọc bối rối hơn while true; do...
    while : colons are more than punctuation; do  
      echo "I love colons"  
      sleep 1  
    done  
    
    while true; do chỉ dài hơn while :; do ba ký tự nên vẫn đủ ngắn, và đoạn mã đó không có vẻ là ví dụ phù hợp với luận điểm tác giả muốn truyền đạt
    • Đây là đoạn mã được đưa vào như trò chơi chữ, không phải ví dụ để làm theo nguyên xi. Nếu hiểu được đoạn mã này thì tức là biết về lệnh null, và dấu hai chấm thực sự có ý nghĩa hơn cả dấu câu
    • Thứ vốn định minh họa là một vòng lặp vô hạn như sau, nhưng có vẻ vì muốn diễn đạt cho ngầu nên đã làm mất trọng tâm
      while :; do  
          something  
      done