我的腳本有問題。
序幕 首先,我有一個 100 行文件列表,如下所示:
100;TEST ONE
101;TEST TWO
...
200;TEST HUNDRED
每行有 2 個參數。例如,第一行的參數是:「645」、「TEST ONE」。所以分號是分隔符號。
我需要將兩個參數放入兩個變數中。假設它將是 $id 和 $name。對於每一行,$id 和 $name 值都會不同。例如,對於第二行 $id = "646" 和 $name = "TEST TWO"。
之後,我需要取得範例檔案並將預定義關鍵字變更為 $id 和 $name 值。範例文件如下所示:
xxx is yyy
因此我想要 100 個具有不同內容的檔案。每個文件必須包含每一行的 $id 和 $name 資料。並且它必須由它的 $name 值命名。
有我的腳本:
#!/bin/bash -x
rm -f output/*
for i in $(cat list)
do
id="$(printf "$i" | awk -F ';' '{print $1}')"
name="$(printf "$i" | awk -F ';' '{print $2}')"
cp sample.xml output/input.tmp
sed -i -e "s/xxx/$id/g" output/input.tmp
sed -i -e "s/yyy/$name/g" output/input.tmp
mv output/input.tmp output/$name.xml
done
所以,我只是嘗試逐行讀取我的列表文件。對於每一行,我都會獲得兩個變量,然後使用它們替換範例檔案中的關鍵字(xxx 和 yyy),然後儲存結果。
但出了點問題
結果我只有 1 個輸出檔。而且調試看起來很糟。
這是調試窗口,我的列表文件中只有 2 行。我只得到一個輸出檔。檔案名稱只是“TEST”,它包含一個字串:“101 is TEST”。
需要兩個檔案:“測試一”、“測試二”,並且必須包含“100 是測試一”和“101 是測試二”。
如您所看到的,第二個變數中有一個空格(例如“TEST ONE”)。我認為這個問題與空間特殊符號有關,但我不知道為什麼。我將 -F awk 參數設為“;”,因此 awk 必須僅將分號解釋為分隔符號!
我做錯了什麼?
答案1
如果我理解正確的話,您可以使用 while 循環和變數擴展
while IFS= read -r line; do
id="${line%;*}"
name="${line#*;}"
cp sample.xml output/input.tmp
sed -i -e "s/xxx/$id/g" output/input.tmp
sed -i -e "s/yyy/$name/g" output/input.tmp
mv output/input.tmp output/"$name".xml
done < file
正如@steeldriver 所提議的,這是一個(更優雅的)選項:
while IFS=';' read -r id name; do
cp sample.xml output/input.tmp
sed -i -e "s/xxx/$id/g" output/input.tmp
sed -i -e "s/yyy/$name/g" output/input.tmp
mv output/input.tmp output/"$name".xml
done < file
答案2
引用!這一行的引用遺失了:
mv output/input.tmp output/$name.xml
它應該是:
mv output/input.tmp output/"$name".xml
以避免檔案名稱帶有空格的問題。
並且, 的展開$(cat list)
被外殼分割(和成團),這也打破了空間。
也許你可以更改為這個腳本:
#!/bin/bash -x
rm -f output/*
inputfile=output/input.tmp
while read -r line
do
id=${line%%;*}
name=${line##*;}
cp sample.xml "$inputfile"
sed -i -e "s/xxx/$id/g" "$inputfile"
sed -i -e "s/yyy/$name/g" "$inputfile"
mv "$inputfile" output/"$name".xml; echo
done <list
答案3
awk 未產生預期結果的原因是您迭代文件的方式。當您使用 進行迭代時for i in $(cat file)
,您是在單字(由 IFS 分割)上迭代,而不是在行上迭代。若要逐行讀取文件,請使用while read
:
while read -r line; do
...
done < file
如需進一步閱讀,請參閱以下 bash 常見問題:如何逐行(和/或逐字段)讀取檔案(資料流、變數)?
答案4
作為一種替代方法,你可以用 awk 完成這項工作在 1 個進程中,而不是每行 4 個進程中。如果清單中有很多行但 example.xml 很小,這很可能是有益的。
awk -F';' 'FNR==NR{x=x $0 RS; next}
{t=x; gsub(/xxx/,$1,t); gsub(/yyy/,$2,t); f="output/"$2".xml"; printf "%s",t >f; close(f)}
' sample.xml list
# shown with unnecessary linebreaks for clarity, but you can put it all on one line
如果清單具有 CRLF 行結尾(又稱 DOS 或 Windows 格式),如您的 Q 上所註釋的那樣,並且您不能(輕鬆)或不想先刪除它們,awk 也可以處理它;就在第二次{
插入之後sub(/\r$/,"",$0);
(或者$2
如果您願意的話)。
perl 也可以做到這一點(perl 幾乎可以完成 awk 可以做的所有事情),但稍微冗長一些,雖然 perl 很常用,但它不像 awk 那樣是 POSIX。