Bash為什麼
為什麼echo -ne 'commit $(git cat-file commit cc540cb | wc -c)0'
在命令替換之前輸出空格?
為了學習 Git 的內部工作原理,我想按照這個SO 答案的描述手動計算送出雜湊。
但是,在
printf
工作時(見下文),我得到了奇怪的行為echo
,它在命令替換之前輸出空格。為什麼
echo
在輸出中嵌入這些空格?不正確的 (
echo
):$ (echo -ne "commit $(git cat-file commit cc540cb | wc -c)\0"; git cat-file commit cc540cb) | hexdump -Cv 00000000 63 6f 6d 6d 69 74 20 20 20 20 20 20 32 31 38 00 |commit 218.| 00000010 74 72 65 65 20 34 35 64 38 62 30 35 38 32 65 32 |tree 45d8b0582e2| 00000020 34 62 39 61 66 66 38 62 34 64 34 65 35 66 33 31 |4b9aff8b4d4e5f31| 00000030 65 35 38 64 62 38 37 38 61 33 64 32 35 0a 70 61 |e58db878a3d25.pa| 00000040 72 65 6e 74 20 64 64 31 37 31 64 61 35 62 61 64 |rent dd171da5bad| 00000050 31 34 62 36 30 37 36 65 64 64 36 30 66 35 38 33 |14b6076edd60f583| 00000060 33 63 39 33 63 65 38 33 61 36 66 64 61 0a 61 75 |3c93ce83a6fda.au| 00000070 74 68 6f 72 20 6e 6c 79 6b 6b 65 69 20 3c 6e 6c |thor nlykkei <nl| 00000080 79 6b 6b 65 69 40 67 6d 61 69 6c 2e 63 6f 6d 3e |ykkei@gmail.com>| 00000090 20 31 35 38 36 37 30 33 39 31 39 20 2b 30 32 30 | 1586703919 +020| 000000a0 30 0a 63 6f 6d 6d 69 74 74 65 72 20 6e 6c 79 6b |0.committer nlyk| 000000b0 6b 65 69 20 3c 6e 6c 79 6b 6b 65 69 40 67 6d 61 |kei <nlykkei@gma| 000000c0 69 6c 2e 63 6f 6d 3e 20 31 35 38 36 37 30 37 34 |il.com> 15867074| 000000d0 35 38 20 2b 30 32 30 30 0a 0a 41 77 65 73 6f 6d |58 +0200..Awesom| 000000e0 65 20 72 65 62 61 73 65 21 0a |e rebase!.| 000000ea
正確的 (
printf
):$ (printf "commit %s\0" $(git cat-file commit cc540cb | wc -c); git cat-file commit cc540cb) | hexdump -Cv 00000000 63 6f 6d 6d 69 74 20 32 31 38 00 74 72 65 65 20 |commit 218.tree | 00000010 34 35 64 38 62 30 35 38 32 65 32 34 62 39 61 66 |45d8b0582e24b9af| 00000020 66 38 62 34 64 34 65 35 66 33 31 65 35 38 64 62 |f8b4d4e5f31e58db| 00000030 38 37 38 61 33 64 32 35 0a 70 61 72 65 6e 74 20 |878a3d25.parent | 00000040 64 64 31 37 31 64 61 35 62 61 64 31 34 62 36 30 |dd171da5bad14b60| 00000050 37 36 65 64 64 36 30 66 35 38 33 33 63 39 33 63 |76edd60f5833c93c| 00000060 65 38 33 61 36 66 64 61 0a 61 75 74 68 6f 72 20 |e83a6fda.author | 00000070 6e 6c 79 6b 6b 65 69 20 3c 6e 6c 79 6b 6b 65 69 |nlykkei <nlykkei| 00000080 40 67 6d 61 69 6c 2e 63 6f 6d 3e 20 31 35 38 36 |@gmail.com> 1586| 00000090 37 30 33 39 31 39 20 2b 30 32 30 30 0a 63 6f 6d |703919 +0200.com| 000000a0 6d 69 74 74 65 72 20 6e 6c 79 6b 6b 65 69 20 3c |mitter nlykkei <| 000000b0 6e 6c 79 6b 6b 65 69 40 67 6d 61 69 6c 2e 63 6f |nlykkei@gmail.co| 000000c0 6d 3e 20 31 35 38 36 37 30 37 34 35 38 20 2b 30 |m> 1586707458 +0| 000000d0 32 30 30 0a 0a 41 77 65 73 6f 6d 65 20 72 65 62 |200..Awesome reb| 000000e0 61 73 65 21 0a |ase!.| 000000e5
wc -c
在數字前輸出空格:$ wc -c <file 6
在您的第一個命令中,字元串
commit
和 的輸出wc -c
保存在雙引號字元串中。在您的第二個命令中,
wc -c
使用未引用的輸出。在不帶引號的上下文中,shell 會
$IFS
在使用結果單詞之前將輸出拆分為 中的字元,其中包括一個空格。(它也會對單詞進行文件名通配,但這在這裡無關緊要)。如果您引用命令替換,您將使用第二個命令獲得相同的輸出。
儘管您認為帶有
printf
, 的第二個命令是“正確的”,但不引用命令替換通常是一個壞主意,因為 shell 會進行拆分和通配。我建議引用命令替換(因為這始終是一個好習慣),而是從以下輸出中顯式刪除空格
wc -c
:(printf "commit %s\0" "$(git cat-file commit cc540cb | wc -c | tr -d ' ')"; git cat-file commit cc540cb) | hexdump -Cv