Vấn đề về echo và printf chỉ liên quan đến sự hiểu biết khi một ký tự được trích dẫn trở lại là một "ký tự đặc biệt".
Đơn giản nhất là với một chuỗi trong printf '%s' "$string"
.
Trong trường hợp này, không có ký tự đặc biệt nào để xử lý và mọi thứ mà lệnh printf nhận được trong đối số thứ hai được in nguyên trạng.
Lưu ý rằng chỉ có dấu ngoặc đơn được sử dụng:
$ printf '%s\n' '\\\\\\\\\T ' # nine \
\\\\\\\\\T # nine \
Khi chuỗi được sử dụng làm đối số đầu tiên, một số ký tự là đặc biệt.
Một \\
cặp đại diện cho một đơn \
và \T
một đơn T
:
$ printf '\\\\\\\\\T ' # nine \
\\\\T # four \
Mỗi cặp trong số bốn cặp \\
biến đổi thành một \
và cuối cùng \T
thành a T
.
$ printf '\\\\\\\\\a ' # nine \
\\\\ # four \
Mỗi trong số bốn cặp \\
biến đổi thành một ký tự duy nhất \
và cuối cùng \a
thành một ký tự chuông (BEL) (không in được).
Điều tương tự xảy ra với một số thực hiện tiếng vang.
Việc thực hiện dấu gạch ngang luôn biến đổi các ký tự dấu gạch chéo ngược đặc biệt.
Nếu chúng ta đặt mã này trong một tập lệnh:
set -- '\g ' '\\g ' '\\\g ' '\\\\g ' '\\\\\g ' '\\\\\\g ' '\\\\\\\g ' '\\\\\\\\g ' '\\\\\\\\\g '
for i ; do
printf '<%-14s> \t<%-9s> \t<%-14s> \t<%-12s>\n' \
"$(printf '%s ' "|$i|")" \
"$(printf "|$i|")" \
"$(echo "|$i|")" \
"$(echo -e "|$i|")" ;
done
Sau đó, dấu gạch ngang sẽ in ( dash ./script
):
<|\g | > <|\g | > <|\g | > <-e |\g | >
<|\\g | > <|\g | > <|\g | > <-e |\g | >
<|\\\g | > <|\\g | > <|\\g | > <-e |\\g | >
<|\\\\g | > <|\\g | > <|\\g | > <-e |\\g | >
<|\\\\\g | > <|\\\g | > <|\\\g | > <-e |\\\g | >
<|\\\\\\g | > <|\\\g | > <|\\\g | > <-e |\\\g | >
<|\\\\\\\g | > <|\\\\g | > <|\\\\g | > <-e |\\\\g | >
<|\\\\\\\\g | > <|\\\\g | > <|\\\\g | > <-e |\\\\g | >
<|\\\\\\\\\g | > <|\\\\\g |> <|\\\\\g | > <-e |\\\\\g |>
Hai cột đầu tiên sẽ giống nhau (printf) cho tất cả các shell.
Hai cái còn lại sẽ thay đổi với việc thực hiện cụ thể của tiếng vang được sử dụng.
Ví dụ: ash ./script
(busybox ash):
<|\g | > <|\g | > <|\g | > <|\g | >
<|\\g | > <|\g | > <|\\g | > <|\g | >
<|\\\g | > <|\\g | > <|\\\g | > <|\\g | >
<|\\\\g | > <|\\g | > <|\\\\g | > <|\\g | >
<|\\\\\g | > <|\\\g | > <|\\\\\g | > <|\\\g | >
<|\\\\\\g | > <|\\\g | > <|\\\\\\g | > <|\\\g | >
<|\\\\\\\g | > <|\\\\g | > <|\\\\\\\g | > <|\\\\g | >
<|\\\\\\\\g | > <|\\\\g | > <|\\\\\\\\g | > <|\\\\g | >
<|\\\\\\\\\g | > <|\\\\\g |> <|\\\\\\\\\g | > <|\\\\\g | >
Nếu ký tự được sử dụng là một a
, cho dấu gạch ngang:
<|\a | > <| | > <| | > <-e | | >
<|\\a | > <|\a | > <|\a | > <-e |\a | >
<|\\\a | > <|\ | > <|\ | > <-e |\ | >
<|\\\\a | > <|\\a | > <|\\a | > <-e |\\a | >
<|\\\\\a | > <|\\ | > <|\\ | > <-e |\\ | >
<|\\\\\\a | > <|\\\a | > <|\\\a | > <-e |\\\a | >
<|\\\\\\\a | > <|\\\ | > <|\\\ | > <-e |\\\ | >
<|\\\\\\\\a | > <|\\\\a | > <|\\\\a | > <-e |\\\\a | >
<|\\\\\\\\\a | > <|\\\\ | > <|\\\\ | > <-e |\\\\ | >
Và cho bash:
<|\a | > <| | > <|\a | > <| | >
<|\\a | > <|\a | > <|\\a | > <|\a | >
<|\\\a | > <|\ | > <|\\\a | > <|\ | >
<|\\\\a | > <|\\a | > <|\\\\a | > <|\\a | >
<|\\\\\a | > <|\\ | > <|\\\\\a | > <|\\ | >
<|\\\\\\a | > <|\\\a | > <|\\\\\\a | > <|\\\a | >
<|\\\\\\\a | > <|\\\ | > <|\\\\\\\a | > <|\\\ | >
<|\\\\\\\\a | > <|\\\\a | > <|\\\\\\\\a | > <|\\\\a | >
<|\\\\\\\\\a | > <|\\\\ | > <|\\\\\\\\\a | > <|\\\\ | >
Do đó, chúng ta phải thêm phần giải thích rằng shell là các lệnh đang được thực thi cũng có thể áp dụng cho chuỗi ký tự.
$ printf '%s\n' '\\\\T '
\\\\T
$ printf '%s\n' "\\\\T "
\\T
Lưu ý rằng shell thực hiện một số hành động đối với dấu gạch chéo ngược bên trong dấu ngoặc kép.
Với mã này:
tab=' '
say(){ echo "$(printf '%s' "$a") $tab $(echo "$a") $tab $(echo -e "$a")"; }
a="one \a " ; say
a="two \\a " ; say
a="t33 \\\a " ; say
a="f44 \\\\a " ; say
a="f55 \\\\\a " ; say
a="s66 \\\\\\a " ; say
a="s77 \\\\\\\a " ; say
a="e88 \\\\\\\\a " ; say
a="n99 \\\\\\\\\a " ; say
Cả hai hiệu ứng đều được thêm vào và chúng tôi nhận được điều này:
$ bash ./script
one \a one \a one
two \a two \a two
t33 \\a t33 \\a t33 \a
f44 \\a f44 \\a f44 \a
f55 \\\a f55 \\\a f55 \
s66 \\\a s66 \\\a s66 \
s77 \\\\a s77 \\\\a s77 \\a
e88 \\\\a e88 \\\\a e88 \\a
n99 \\\\\a n99 \\\\\a n99 \\
Đối với dấu gạch ngang, nó thậm chí còn nghiêm trọng hơn:
$ dash ./script
one one -e one
two two -e two
t33 \a t33 -e t33
f44 \a f44 -e f44
f55 \ f55 \ -e f55 \
s66 \ s66 \ -e s66 \
s77 \\a s77 \a -e s77 \a
e88 \\a e88 \a -e e88 \a
n99 \\ n99 \ -e n99 \