我正在尝试根据根目录上的多个文件创建 Excel 工作表。我逐行读取文件并附加到最终的 Excel 工作表中。
我正在小文件上尝试这个 shell 脚本,它运行 100%,但是当我在所需的文件(每个文件 85MB)上尝试它时,我收到此错误:
(dsadm@DEVDS) /EDWH/XML/Must # XML.sh csv excel_outputfilename
./XML.sh: line 41: fallocate: command not found
./XML.sh: xmalloc: cannot allocate 172035663 bytes (0 bytes allocated)
./XML.sh: xrealloc: cannot reallocate 86013568 bytes (0 bytes allocated)
./XML.sh: xrealloc: cannot reallocate 86021888 bytes (0 bytes allocated)
笔记:
参数
csv
为文件扩展名我的操作系统和版本:Unix AIX 7.1
这是脚本:
#!/usr/bin/bash
#Files Extension#
Ext=$1
#OutPut File Name without extension ex: TEST#
OutPutFileName=$2.xls
function XMLHeader ()
{
echo "<?xml version=\"1.0\"?>
<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"
xmlns:o=\"urn:schemas-microsoft-com:office:office\"
xmlns:x=\"urn:schemas-microsoft-com:office:excel\"
xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"
xmlns:html=\"http://www.w3.org/TR/REC-html40\">"
}
function SheetHeader ()
{
echo "<Worksheet ss:Name=\"Sheet1\">
<Table ss:ExpandedColumnCount=\"2\" ss:ExpandedRowCount=\"2\" x:FullColumns=\"1\" x:FullRows=\"1\">
<Row><Cell><Data ss:Type=\"String\">"
}
function SheetFooter ()
{
echo "</Data></Cell></Row></Table>
</Worksheet>"
}
function XMLFooter ()
{
echo "</Workbook>"
}
####################################################################################
cd /EDWH/Samir/XML/Must;
fallocate -l 1G $OutPutFileName
XMLHeader > $OutPutFileName;
# loop on the exists files to build Worksheet per each file
for Vfile in $(ls | grep .$Ext);
do
echo "<Worksheet ss:Name=\"$Vfile\"><Table>" >> $OutPutFileName
### loop to write the Row
VarRow=`cat $Vfile`
for Row in $(echo $VarRow )
do
echo "<Row>" >> $OutPutFileName
### loop to write the cells
VarCell=`echo $VarRow`
for Cell in $(echo $VarCell | sed "s/,/ /g")
do
echo "<Cell><Data ss:Type=\"String\">$Cell</Data></Cell>" >> $OutPutFileName
done
echo "</Row>" >> $OutPutFileName
done
echo "</Table></Worksheet>" >> $OutPutFileName
done
echo "</Workbook>" >> $OutPutFileName
####################################################################################
exit;
答案1
仅介绍有关此脚本的一些信息,忽略它是处理 XML 的 shell 脚本。
- 它将每个文件读入内存。
- 它使用了一些“不好的做法”的结构。
让我们解决这个问题。
首先,每个命令不需要以
;
.如果;
您将多个命令放在一行上,例如ls; echo "hello"
.变量扩展应始终用双引号引起来。看 ”忘记在 bash/POSIX shell 中引用变量的安全隐患”。例如:
Ext="$1"
、XMLHeader >"$OutPutFileName"
等。for Vfile in $(ls | grep .$Ext)
写得比较好for Vfile in ./*."$Ext"
。不要在循环中执行多个重定向,将所有重定向都附加到同一文件,而是以
done >>"$OutPutFileName"
.这样效率更高。VarRow=`cat $Vfile`
会将 85Mb 文件的内容放入单个变量中,然后for Row in $(echo $VarRow )
循环遍历行,或者您希望如此。相反,做while IFS= read -r Row; do ... done <"$Vfile"
.这将一次读取一行。您一次只存储一行,而不是存储整个文件。这可能是您遇到内存问题的地方。而不是
VarCell=`echo $VarRow`
紧随其后for Cell in $(echo $VarCell | sed "s/,/ /g")
,只需执行VarCell="${VarRow//,/ }"
紧随其后for Cell in $VarCell
(这感觉有点不确定,一个未加引号的变量保存输入数据,欢迎提出改进建议)任何
echo
输出变量数据的内容,我都会更改printf
为单引号格式字符串,后跟双引号变量扩展。例如:echo "<Worksheet ss:Name=\"$Vfile\"><Table>"
更改为printf '<Worksheet ss:Name="%s"><Table>\n' "$VFile"
.看 ”为什么 printf 比 echo 更好?”。当您想要输出长字符串(几行)时,请使用此处文档。这样您就不必担心转义引号。