Bash技巧:把變數賦值為換行符,判斷檔案是否以換行符結尾

霜魚片發表於2020-08-17

把變數賦值為換行符

在 bash 中,如果要把變數賦值為換行符,寫為 '\n' 沒有效果,需要寫為 $'\n'。具體舉例如下:

$ newline='\n'
$ echo $newline
\n
$ newline=$'\n'
$ echo $newline

可以看到,把 newline 變數賦值為 'n',得到的是 n 這個字串,而不是換行符自身。

這是 bash 和 C 語言不一樣的地方。
在 C 語言中,'n' 對應換行符自身,只有一個字元;而 "n" 對應一個字串。
但是在 bash 中,'n' 也是對應一個字串。

newline 賦值為 $'\n',就能獲取到換行符自身。檢視 man bash 對這個寫法的說明如下:

Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded as follows:
    \n     new line
    \r     carriage return
    \t     horizontal tab
    \'     single quote
The expanded result is single-quoted, as if the dollar sign had not been present.

即,$'string' 這個寫法可以使用 C 語言的轉義字元來獲取到對應的字元自身。

判斷檔案的最後一行是否以換行符結尾

在 Linux 中,可以使用下面命令來判斷檔案的最後一行是否以換行符結尾:

test -n "$(tail filename -c 1)"

這裡使用 tail filename -c 1 命令獲取到 filename 檔案的最後一個字元。

實際使用時,需要把 filename 換成具體要判斷的檔名。

tail 命令可以獲取檔案末尾的內容。它的 -c 選項指定要獲取檔案末尾的多少個位元組。

檢視 man tail 對 -c 選項的說明如下:

-c, --bytes=K

output the last K bytes; alternatively, use -c +K to output bytes starting with the Kth of each file.

即,tail -c 1 命令指定獲取所給檔案的最後一個字元。

獲取到檔案的最後一個字元後,要判斷該字元是不是換行符。這裡不能直接判斷該字元是否等於換行符,而是要判斷該字元是否為空。

原因在於,使用 $(tail filename -c 1) 命令替換來獲取內部命令的輸出結果時,bash 會去掉末尾的換行符。

所以當檔案的最後一行以換行符結尾時,$(tail filename -c 1) 命令替換會去掉獲取到的換行符,最終結果為空,並不會返回換行符自身。

檢視 man bash 對命令替換(command substitution)的說明如下:

Command substitution allows the output of a command to replace the command name. There are two forms:
        $(command)
    or
        `command`
Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted. Embedded newlines are not deleted, but they may be removed during word splitting.

可以看到,經過命令替換後,會去掉末尾的換行符。

由於 $(tail filename -c 1) 命令替換會去掉末尾的換行符,這裡使用 test -n 來判斷最終結果是否為空字串。

如果檔案最後一行以換行符結尾,那麼 $(tail filename -c 1) 的結果為空,test -n 命令會返回 1,也就是 false。

如果檔案最後一行沒有以換行符結尾,那麼 $(tail filename -c 1) 的結果不為空,test -n 命令會返回 0,也就是 true。

可以根據實際需要,改用 test -z 來判斷。如果檔案最後一行以換行符結尾,$(tail filename -c 1) 的結果為空,test -z 命令會返回 0,也就是 true。

相關文章