excel - 如何在 cygwin 下使用 awk 打印 Excel 电子表格中的字段?

标签 excel csv awk vbscript cygwin

我们似乎看到越来越多有关在 Excel 电子表格上执行 awk 的问题,因此这里有一个关于如何执行该特定操作的问答。

我在 Excel 电子表格中包含此信息“$D/staff.xlsx”(其中 “$D” 是我的桌面的路径):

Name   Position
Sue    Manager
Bill   Secretary
Pat    Engineer

并且我想打印给定名称的位置字段,例如给定输入 Bill,输出 Secretary

我目前可以从 Excel 保存为 CSV 以获得:

$ cat "$D/staff.csv"
Name,Position
Sue,Manager
Bill,Secretary
Pat,Engineer

然后运行:

$ awk -F, -v name="Bill" '$1==name{print $2}' "$D/staff.csv"
Secretary

但这只是更大任务的一小部分,因此我必须能够从 shell 脚本自动执行此操作,而无需手动打开 Excel 导出 CSV 文件。如何在运行 cygwin 的 Windows PC 上执行此操作?

最佳答案

以下 VBS 和 shell 脚本的组合为 Excel 电子表格中的每个工作表创建一个 CSV 文件:

$ cat xls2csv.vbs
csv_format = 6

Dim strFilename
Dim objFSO
Set objFSO = CreateObject("scripting.filesystemobject")
strFilename = objFSO.GetAbsolutePathName(WScript.Arguments(0))
If objFSO.fileexists(strFilename) Then
  Call Writefile(strFilename)
Else
  wscript.echo "no such file!"
End If
Set objFSO = Nothing

Sub Writefile(ByVal strFilename)
Dim objExcel
Dim objWB
Dim objws

Set objExcel = CreateObject("Excel.Application")
Set objWB = objExcel.Workbooks.Open(strFilename)

For Each objws In objWB.Sheets
  objws.Copy
  objExcel.ActiveWorkbook.SaveAs objWB.Path & "\" & objws.Name & ".csv", csv_format
  objExcel.ActiveWorkbook.Close False
Next

objWB.Close False
objExcel.Quit
Set objExcel = Nothing
End Sub

.

$ cat xls2csv
PATH="$HOME:$PATH"

# the original XLS input file path components
inXlsPath="$1"
inXlsDir=$(dirname "$inXlsPath")
xlsFile=$(basename "$inXlsPath")
xlsBase="${xlsFile%.*}"

# The tmp dir we'll copy the XLS to and run the tool on
# to get the CSVs generated
tmpXlsDir="/usr/tmp/${xlsBase}.$$"
tmpXlsPath="${tmpXlsDir}/${xlsFile}"
absXlsPath="C:/cygwin64/${tmpXlsPath}" # need an absolute path for VBS to work

mkdir -p "$tmpXlsDir"

trap 'rm -f "${tmpXlsDir}/${xlsFile}"; rmdir "$tmpXlsDir"; exit' 0

cp "$inXlsPath" "$tmpXlsDir"

cygstart "$HOME/xls2csv.vbs" "$absXlsPath"

printf "Waiting for \"${tmpXlsDir}/~\$${xlsFile}\" to be created:\n" >&2
while [ ! -f "${tmpXlsDir}/~\$${xlsFile}" ]
do
    # VBS is done when this tmp file is created and later removed
    printf "." >&2
    sleep 1
done
printf " Done.\n" >&2

printf "Waiting for \"${tmpXlsDir}/~\$${xlsFile}\" to be removed:\n" >&2
while [ -f "${tmpXlsDir}/~\$${xlsFile}" ]
do
    # VBS is done when this tmp file is removed
    printf "." >&2
    sleep 1
done
printf " Done.\n" >&2

numFiles=0
for file in "$tmpXlsDir"/*.csv
do
    numFiles=$(( numFiles + 1 ))
done

if (( numFiles >= 1 ))
then
    outCsvDir="${inXlsDir}/${xlsBase}.csvs"
    mkdir -p "$outCsvDir"
    mv "$tmpXlsDir"/*.csv "$outCsvDir"
fi

现在我们执行 shell 脚本,该脚本内部调用 cygstart 来运行 VBS 脚本,以在 Excel 文件所在目录下的子目录中生成 CSV 文件(每张一个),该子目录根据 Excel 文件名命名(例如 Excel文件 staff.xlsx 生成 CSV 目录 staff.csvs):

$ ./xls2csv "$D/staff.xlsx"
Waiting for "/usr/tmp/staff.2700/~$staff.xlsx" to be created:
.. Done.
Waiting for "/usr/tmp/staff.2700/~$staff.xlsx" to be removed:
. Done.

目标 Excel 文件 "$D/staff.xlsx" 中只有一张默认名称为 Sheet1 的工作表,因此上面的输出是一个文件 “$D/staff.csvs/Sheet1.csv”:

$ cat "$D/staff.csvs/Sheet1.csv"
Name,Position
Sue,Manager
Bill,Secretary
Pat,Engineer

$ awk -F, -v name="Bill" '$1==name{print $2}' "$D/staff.csvs/Sheet1.csv"
Secretary

另请参阅What's the most robust way to efficiently parse CSV using awk?了解如何操作这些 CSV。

另请参阅https://stackoverflow.com/a/58879683/1745001了解如何执行相反的操作,即从 Windows 批处理文件调用 cygwin bash 命令。

关于excel - 如何在 cygwin 下使用 awk 打印 Excel 电子表格中的字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38805123/

相关文章:

bash - unix bash shell 脚本中的惰性匹配

regex - 搜索并追加新行 Linux

arrays - 使用 VBA 将二维数组卸载到 Excel 工作表中的最快方法是什么?

vba - 隐藏框架时无法设置可见属性错误

mysql - 将 CSV 导出到 MySQL

python - 使用 DictReader 从 CSV 文件读取到列表中

linux - 使用 sed、awk 和 xargs 切片 3TB 日志文件?

excel - 从另一个 Sub 调用/引用命名范围

升级到 Office 2013 后 Excel 宏不起作用

sql - 列上的完整数据