shell編程中星號(asterisk "*")的坑


今天分享一個有關shell編程中由通配符引起的問題。

1. 問題代碼

cat test.logs

4567890 *
##*************************************##
rtyuio**tyuio432
##*************************************##
*rtyuiop*2* yuiop
##*************************************##
rtyuiop(3 * 4)iuytr
##*************************************##
8765432

cat script.sh

#!/usr/bin/env bash

# 主要功能是將 非##開頭 的每行記錄寫入到文件中,每個文件保存一行記錄
logsname=test.logs
i=100
while read line
do
    if [[ $line =~ '##' ]];then
        ((i++))
    else
        echo $line >> $i.txt
    fi
done < "${logsname}"

運行script.sh腳本的結果:
問題運行結果

從圖片上紅框部分可以看到:

4567890 * 被替換為 4567890 script.sh test.logs
rtyuiop(3 * 4)iuytr 被替換為 rtyuiop(3 100.txt 101.txt 102.txt script.sh test.logs 4)iuytr

其他行都正常打印結果,為什么這兩行會有問題呢?其他行也有星號,為什么沒有被替換呢?

2. 原因分析

根據輸出結果可以判斷出問題的代碼:echo $line >> $i.txt

首先,介紹一下shell執行腳本的原理:

  1. shell讀取整個腳本文件,然后從上到下依次執行每一行
  2. 假設當前line=4567890 *,當shell執行echo $line >> $i.txt
    1. 首先,shell負責替換$line的值為:4567890 *,此時代碼是:echo 4567890 * >> $i.txt
    2. 然后,shell在執行echo命令之前,檢查命令的參數中是否有通配符(PS:此時echo的參數:4567890 *)
    3. 很明顯,*是通配符,shell負責解析通配符,shell會將通配符當作路徑或文件名在磁盤上搜尋可能的匹配:若符合要求的匹配存在,則進行替換(路徑擴展);否則就將該通配符作為一個普通字符參數傳遞給echo,然后再由echo進行處理。
    4. 解析完通配符后,*被替換為script.sh test.logs,此時echo命令的參數是:4567890 script.sh test.logs
    5. 最后,shell執行echo 4567890 script.sh test.logs,然后將echo命令執行的結果重定向到文件中。

Tips:

通配符看起來有點像正則表達式,但是它與正則表達式不同的,不能相互混淆。可以把通配符理解為shell能夠處理的特殊字符。而且shell的通配符涉及的只有 "*, ?, [], {}" 這幾種。

通配符是shell自身支持的,而正則表達式需要相關工具的支持:grep,awk,vi,perl。在文本過濾工具里,都是用正則表達式,比如像awk,sed等,正則表達式是針對文件的內容通配符多用於文件名或者路徑上,比如查找find,ls,cp等。

3. 解決方案

根據上面的分析可以知道,$line被替換后,通配符*再次被shell解析。那有什么辦法可以防止shell解析通配符呢?

  1. 使用引用變量:"$line"在兩端加上引號,這樣"$line"就變成了一個字符串"4567890 *",而不是兩個單獨的字符串。
  2. 引用變量可防止分詞和通配符擴展(也就是shell解析通配符),並且可以防止在變量中包含空格、換行符、通配符等時造成腳本中斷。
  3. 在shell編程中總是使用引用變量的方式,這是一個良好又安全的編碼習慣。

4. 參考資料

  1. Reading asterisk character (*) from a file in bash
  2. When to wrap quotes around a shell variable?
  3. Security implications of forgetting to quote a variable in bash/POSIX shells
  4. shellcheck.net-finds bugs in your shell scripts.
  5. Linux Shell 通配符、元字符、轉義符使用實例介紹


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM