0

我需要创建这个脚本,然后输出到 template.vars 中的 html 文件数据。该脚本是一个模板引擎,但现在它所做的只是从键盘输入输入,当输入为@NAME@ 时,在 template.vars 中回显名称。下面是目前模板引擎的代码:

#!/bin/bash
IFS=@  #makes @ a delimiter. 
while read line
do
  dataspace=$(awk '$0=$1' FS== <<< "$line")
    value=$(awk '$0=$2' FS== <<< "$line")
  printf -v $dataspace "$value"                     #make the value stored in value into the name of a dataspace.
done < 'template.vars' #read template.vars for standard input.
skipflag=false           #initialize the skipflag to false                       
while read line                                 #while it is reading standard input one line at a time
do
  read -a dataspacearray <<< "$line"                #make the line into an array.
  if [ $skipflag == false ] && [ "${dataspacearray[1]}" != "ENDIF" ] ; then
        if [[ ${dataspacearray[1]} == "IF "* ]] ; then #If second element of dataspacearray is "IF "(something)
          dataspace=`echo ${dataspacearray[1]} | cut -d' ' -f2`
          if [ -z "${!dataspace}" ] ; then                #if dataspace not found, skip everything up to endif. -z to test string
            skipflag=true
            fi
        else
          for ((i=0; i<${#dataspacearray[@]}; i++))
          do
            dataspace=${dataspacearray[i]}                    #access to each dataspace in the array
            even=`expr $i % 2`  
                    if [ $even == '0' ] ; then                #if it's even(f0,f2, f4.. etc. etc) then it's not a variable, so print it directly
              if [ -n "${dataspace}" ] ; then
                printf ${dataspace}
              fi
            else                                      #(odd dataspaces(f1, f3... etc.) are variables, print their values if they exist
              if [ -n "${!dataspace}" ] ; then
                printf ${!dataspace}
              else
                printf "Error!!!"
              fi
            fi
          done
          printf "\n"
        fi
  else     
    skipflag=false
  fi
done

html 文件作为输入输入,如下所示:

<html>
  <head>
    <title>@NAME@</title>
  </head>
  <body>
    <p>Name: @NAME@</p>
    <p>Major: @MAJOR@</p>
    <p>Classification: @CLASS@</p>
    <p>Graduation date: @GDATE@</p>
@IF HONORS@
    <p>Graduating with Honors</p>
@ENDIF@
  </body>
</html>

脚本使用 template.vars 文件中的数据替换所有以 @ 开头和结尾的字符串(或输出错误!!!如果未找到)。我见过很多例子,其中模板替换了开头有 $ 的任何文本,并且认为我需要实现类似的东西,但它会读取 html 文件作为输入,然后将其保存为输出。我该怎么做呢?

4

1 回答 1

1

严格来说,这并不是您所要求的,但它可能足够接近,可以为您提供一些工作。

撇开@IF ...@ ... @ENDIF@ 处理(这是一个几乎未经测试的事后考虑),逻辑是这样的:

对于每个输入行

1)初始化一个空的容纳空间

2) 如果该行的分隔符少于两个,转到#10

3)从行首复制到(但不包括)第一个分隔符到保留空间

4) 删除该行的第一段(包括分隔符)。该行的前导段现在应该是一个标记。

5)将令牌(直到分隔符)复制到临时变量

6)从行中删除标记(保留尾随分隔符)

7) 在已知标记列表中查找标记。

8) 如果它是已知标记,则将标记的扩展附加到保留空间并从行中删除分隔符。如果令牌未知,则将定界符(在 #4 处删除)和令牌文本附加到保留空间,但将非令牌的尾随定界符留在行首——这是为了允许 (@name@@@domain @) 并使用不同的变量定义文件(./expstuff -v user.vars < template.in | ./expstuff -v global.vars > outputfile)多次运行,但需要根据您的要求进行更改。

9) 转到#2

10)打印保持空间和行的任何剩余部分。

typeset -A s

i=template.vars
d=@

while IFS='=' read t v ; do
  [[ $t != \#* ]] && s[$t]=$v
done < "$i"

while IFS= read -r l ; do
  #  assuming the @IF blah@ and corresponding @ENDIF@ occupy entire lines.
  if [[ $l == $d[Ee][Nn][Dd][Ii][Ff]$d ]]; then
    c=''
    continue
  fi
  [[ $c == '0' ]] && continue
  if [[ $l == $d[Ii][Ff][[:space:]]*[![:space:]]*$d ]]; then
    read _ t <<< "${l%$d}"
    c=0
    if [[ -n $t && ${s[$t]+t} == 't' ]]; then
      case ${s[$t]} in [Yy]|[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|1 ) c=1 ;; esac
    fi
    continue
  fi

  # Currently, given
  #   foo@domain@TLD@ wibble
  # with TLD=.co.uk
  # the following loop outputs
  #   foo@domain.co.uk wibble
  # You appear to require
  #   fooError!!!TLD@wibble

  h=
  while [[ $l == *$d*$d* ]]; do
    h=$h${l%%$d*}
    l=${l#*$d}
    t=${l%%$d*}
    l=${l#$t}
    if [[ -n $t && ${s[$t]+t} == 't' ]]; then
      h=$h${s[$t]}
      l=${l#$d}
    else
      h=$h$d$t
      # for apparent requirement change preceding line to (untested)
      # h=$h"Error!!!" ; l=${l#$d}
    fi
  done
  printf '%s\n' "$h$l"
done
于 2014-04-12T12:45:48.250 回答