shell指令碼技巧—建立和清空檔案

潇湘隐者發表於2024-10-22

寫這篇文章的起因是因為在分析一個指令碼時,看到這麼一句指令碼,如下所示

................................
>$RMAN_BACKUP/script/rman_backup.sql
................................

最開始我以為它就是將檔案rman_backup.sql清空,這個類似於 cat /dev/null > $RMAN_BACKUP/script/rman_backup.sql命令。但是實際除錯過程發現它的功能不侷限於此。其實它的功能為:如果檔案不存在時建立這麼一個空檔案,如果檔案存在時清空該檔案。猜測編寫者就是想透過這麼一句簡單程式碼去實現這樣的兩個功能,他都懶得去寫一段邏輯判斷:"如果檔案不存在就建立空的檔案,如果檔案存在就清空檔案"。說這個指令碼精妙吧,倒也談不上。但是也確實夠精簡,代價就是閱讀起來晦澀難懂。尤其對shell指令碼不精通的人。只是shell程式設計中確實有一些奇淫技巧.這裡不談其優點與缺點,存在既是合理。

那麼在shell中,有哪些建立檔案的技巧呢?下面簡單總結一下,方便以後編寫shell指令碼時使用,也方便你閱讀shell程式碼。

方法1

touch命令可以用來建立一個空檔案,如果檔案已經存在,則會更新其時間戳。

案例

if [ ${MYSQL_SERVICE_EXISTS} -eq 1 ] && [ -f "$MYSQL_SERVICE_FILE" ]; then
touch /usr/lib/systemd/system/mysqld.service
chmod 644 /usr/lib/systemd/system/mysqld.service
cat >/usr/lib/systemd/system/mysqld.service <<EOF
..................................
..................................
fi

方法2:

使用>重定向運算子將輸出重定向到一個檔案,如果這個檔案不存在,就建立這個檔案。

案例

................................
echo "[error]:`date '+%Y%m%d %H:%M:%S'`> $log_msg" > $LOG_FILE
................................

一般會用上面這種寫法居多,使用最上面那種寫法倒是比較少見。還有一些結合重定向符與其它命令實現的,如下所示

printf "it is test!\n" > filename.txt

方法3:

使用tee命令可以用來讀取標準輸入並將其寫入到檔案和標準輸出。如果檔案不存在,tee命令會建立它

案例

>$RMAN_BACKUP/script/rman_backup.sql
rman_backup |tee -a $RMAN_BACKUP/rman_backup.sql

方法4:

使用cat命令建立一個檔案,如下所示,這裡使用Here Document(<<EOF),它允許你輸入多行文字,直到遇到EOF標記,

案例,建立一個mysqd.service的檔案,並向其寫入一段啟動mysql服務的程式碼。

cat >/usr/lib/systemd/system/mysqld.service <<EOF
[Unit]
Description=MySQL Server
Documentation=man:mysqld(8)
Documentation=http://dev.mysql.com/doc/refman/en/using-systemd.html
After=network.target
After=syslog.target

[Install]
WantedBy=multi-user.target

[Service]
User=mysql
Group=mysql

# Have mysqld write its state to the systemd notify socket
Type=notify

# Disable service start and stop timeout logic of systemd for mysqld service.
TimeoutSec=0

# Start main service
ExecStart=/opt/mysql/mysql8.0/bin/mysqld --defaults-file=/data/mysql/conf/my.cnf $MYSQLD_OPTS

# Use this to switch malloc implementation
EnvironmentFile=-/etc/sysconfig/mysql

# Sets open_files_limit
LimitNOFILE = 100000

Restart=on-failure

RestartPreventExitStatus=1

# Set environment variable MYSQLD_PARENT_PID. This is required for restart.
Environment=MYSQLD_PARENT_PID=1

PrivateTmp=false
EOF

在shell指令碼中,清空檔案有哪些方法呢?一般來說有下面一些方法。

方法1

案例

> mysql_error.log

方法2

案例

echo ''  > mysql_error.log

這個方法比方法1更容易理解,讀懂。

方法3

將/dev/null(一個空裝置檔案)的內容重定向到檔案中,可以清空檔案. 寫法類似這樣:cat /dev/null > filename

案例

if [ -f "${SLOW_LOG_PATH}/${NEW_SLOW_LOG_FILE}_${LOG_ROTATION_DATE}.log" ] ; then 
echo "MySQL慢查詢日誌已經切換(rotation)"
else
cat $SLOW_LOG_PATH/$SLOW_LOG_FILE > $SLOW_LOG_PATH/${NEW_SLOW_LOG_FILE}_${LOG_ROTATION_DATE}.log
#最後執行的命令的結束程式碼(返回值)
if [ $? -eq 0 ]; then
cat /dev/null > $SLOW_LOG_PATH/$SLOW_LOG_FILE
else
echo "failed to empty file"
fi
fi

方法4

truncate命令可以用來減少檔案的大小,將其設定為0位元組,從而清空檔案。

truncate -s 0 mysql_error.log

方法5

: > filename.txt 這種方式來清空檔案.

: > mysql_error.log

其中:表示什麼也不做。前面命令中它會清空檔案內容(截斷檔案);與rm不同,因為rm實際上會完全刪除檔案。 此外,如果檔案不存在,則 :>filename.txt 實際上會建立該檔案。更多關於這個命令的介紹如下所示,參考What is :>filename.txt Doing?[1]文中內容。

As you have discovered, this just empties the file contents (it truncates the file); that is different from rm as rm would actually remove the file altogether. Additionally, :>file.txt will actually create the file if it didn't already exist.

: is a "do nothing command" that will exit with success and produce no output, so it'
s simply a short method to empty a file. In most shells, you could simply do >file.txt to get the same result. It also could be marginally faster than other methods such as echo >file.txt as echo could potentially be an external command.

Additionally, echo >file.txt would put a blank line in file.txt where :>file.txt would make the file have no contents whatsoever.
參考資料
[1]

1: https://unix.stackexchange.com/questions/552436/what-is-filename-txt-doing

相關文章