我目前正在編寫以下腳本。程式碼在某個目錄中尋找使用者輸入的檔案名稱。腳本首先檢查輸入檔案是否為 gzip,如果是,則執行相應的檢查。如果檔案未經過 gzip 壓縮,則會傳回不相容的檔案文字。
我遇到的問題是在線上的7
。無論檔案副檔名如何,我都會收到不相容的檔案作為最終輸出。
#!/bin/bash
DATE=$(date +%Y-%m-%d)
L0_Report_Generator=("/home/ubuntu/$gzip_file")
echo -n "Enter File Directory:"$gzip_file
read $gzip_file
for gzip_file in {$L0_Report_Generator}; do
if [[ $gzip_file = "test_sub"*"gz" ]] #Check file extension for gzip compression
then
gunzip $gzip_file
echo "file Level 0 QC Check"
echo ${DATE}
echo "File Header"
cat $gzip_file | head
echo "Total Records"
cat $gzip_file | wc -l
echo "File Unique Records Size"
cat $L0_Report_Generator | sort -u | wc -l
rm $gzip_file
else [[ $gzip_file != "test_sub"*"gz" ]] #If file is anything other than .gz and csv - rort will not run
then
echo "incompatible file"
fi
done
答案1
如果您想在 if 語句中使用通配符表達式來檢查「.gz」檔案副檔名,那麼您可以使用如下所示的表達式:
if [[ "${gzip_file}" = *.gz ]]; then echo true; else echo false; fi
您可以透過以下方式進行測試:
if [[ "file.gz" = *.gz ]]; then echo true; else echo false; fi
和:
if [[ "file.txt" = *.gz ]]; then echo true; else echo false; fi
第一個範例產生true
其輸出,第二個範例產生false
。
現在讓我們看看您的程式碼。您的 if 語句具有以下條件式:
[[ $gzip_file = "test_sub"*"gz" ]]
特別是,您將“test_sub”作為子字串包含在匹配模式中。嘗試刪除它。
答案2
除了 @igal 所說的有關檢查檔案副檔名的內容之外,您在變數語法和用法方面還有很多錯誤。從第 3 行開始:
L0_Report_Generator=("/home/ubuntu/$gzip_file")
該變數gzip_file
尚未設置,因此$gzip_file
當 shell 展開它時將不會被任何內容取代。另外,中的括號var=(something)
分配一個數組而不是一個普通變量,在這種情況下,這沒有任何意義。
第四行 ,echo -n "Enter File Directory:"$gzip_file
變數 也有同樣的問題gzip_file
。它還存在不可預測的問題echo -n
,在不同版本的命令下會做不同的事情echo
。要列印沒有換行符的字串,最好使用printf "%s" "string to print"
,但在這種情況下,有一個更好的選擇,我稍後會介紹。
第五行read $gzip_file
似乎旨在將使用者輸入讀取到變數 中gzip_file
,但這不是它的作用。在 shell 中,當你放在$
變數名稱前面時,得到變數的當前值。在這裡,你想要放它,所以你必須保留$
off: read gzip_file
。但這不是我會做的。我將包含提示(echo
在第 4 行)作為read
命令的一部分:
read -p "Enter File Directory:" gzip_file
好的,現在是第 6 行:
for gzip_file in {$L0_Report_Generator}; do
這似乎是設置gzip_file
再次read
(替換我們剛剛輸入的值)。您實際上是否嘗試在此處設置gzip_file
,並且之前的變數引用確實應該是不同的變數(也許gzip_dir
相反)?
而且,這in
部分沒有任何意義。我認為您正在嘗試使用變量L0_Report_Generator
,但在這種情況下,左大括號應該去後美元符號。但這也不完全有意義,因為${L0_Report_Generator}
(如果我明白這應該做什麼)只是目錄的路徑。for ... in
不迭代目錄的內容,而是迭代列表字, 喜歡for var in word1 word2 "word 3 which has several spaces in it" word4; do
。如果要取得目錄中的檔案列表,則需要使用通配符,例如for var in dir/*; do
-- shell 會將包含通配符的檔案模式擴展為符合檔案列表,每個檔案都被視為一個單字,並迭代它們。您也可以選擇透過將特定副檔名包含在模式中來限制對具有特定副檔名的檔案的匹配,例如dir/*.gz
.
其他三個注意事項:我建議不要使用大寫變數名稱,例如DATE
, 以避免與對 shell 或某些實用程式具有特殊含義的各種全大寫環境變數發生衝突。另外,始終用雙引號引用變數(即使用"$var"
而不是僅僅$var
)以避免意外的解析異常。且該else
子句沒有測試,因此 usingelse [[ some test ]]
沒有意義(且then
afterelse
是語法錯誤)。
因此,如果我理解腳本應該做什麼,我建議將腳本的開頭替換為:
#!/bin/bash
date=$(date +%Y-%m-%d) # Note lowercase variable
read -p "Enter File Directory:" gzip_dir
L0_Report_Generator="/home/ubuntu/$gzip_dir"
for gzip_file in "${L0_Report_Generator}"/*.gz; do
....然後(如果上面的 .gz 模式是您想要的),您不需要if
檢查是否$gzip_file
具有 .gz 副檔名,因為通配符模式只會列出 .gz 檔案。
還要注意一點:shellcheck.net對於指出 shell 腳本中的基本錯誤非常有幫助。它錯過了我指出的很多內容,但抓住了迷路then
(我最初錯過了)。