BASH:从平面文件导入数据到模板

3
我有一个记录的平面文件,每个记录共 33 行。我需要将此文件格式化成一个模板中的规格。该模板是 DOS 格式,而源文件是 NIX 格式。模板具有特定的缩进和间距,必须遵守。我想了几个选项:
  • 使用经典 nix 工具 BASH: sed、awk、grep 等...
  • 使用模板工具包的 BASH
  • 使用模板工具包的 Perl
  • Perl
这些选项按照我的熟悉程度排序。下面是一个样本源记录( NIX 格式):我减少了换行符的数量以节省空间(通常为 33 行)。
JACKSON HOLE SANITARIUM AND REPTILE ZOO
45 GREASY HOLLER LN
JACKSON HOLE, AK   99999


Change Service Requested


BUBBA HOTEP
3 DELIVERANCE RD
MINNEAPOLIS, MN   99998


BUBBA HOTEP 09090909090909

You have a hold available for pickup as of 2012-01-04:

Title: Banjo for Fun and Profit
Author: Williams, Billy Dee
Price: $10 

这里是模板(DOS格式 - 压缩了行数 - 通常为66行):
     <%BRANCH-NAME%>
     <%BRANCH-ADDR%>
     <%BRANCH-CTY%>


<%CUST-NAME%> <%BARCODE%>
You have a hold available for pickup as of <%DATE%>:

Title: <%TITLE%>
Author: <%AUTHOR%>
Price: <%PRICE%>


             <%CUST-NAME%>
             <%CUST-ADDR%>
             <%CUST-CTY%>

end of file

实际上,每个记录的结尾确实会显示“文件结束”。

你有什么想法?我倾向于过度复杂化事情。

更新2

找到解决方法了。

我的答案如下。欢迎提出改进意见。


也许可以使用命令行中的PHP?如果做得好,它会为未来的Web界面提供一个可重用的组件,而且是免费的... - Eugen Rieck
谢谢您的建议Eugen,但我不会将这些东西网页化,也不懂PHP。 - Bubnoff
当你说“按照模板规格格式化文件”时,你想要对包含记录的文件做什么? - jaypal singh
我需要将记录格式化以匹配模板记录。我的想法是首先创建模板(已完成),其次从文件中提取每个记录,将其输入模板,最后将格式化的记录连接到新文件中。 - Bubnoff
2
Perl是一个经典的Unix工具。 - ikegami
显示剩余7条评论
2个回答

1
作为入门,这里有一个提示:Perl HERE-documents(仅显示一些替换作为演示):
#!/usr/bin/perl
use strict;
use warnings;

my @lines = qw/branchname cust_name barcode bogus whatever/; # (<>);

my ($branchname, $cust_name, $barcode, undef, $whatever) = @lines;

print <<TEMPLATE;
     $branchname
     <%BRANCH-ADDR%>
     <%BRANCH-CTY%>


$cust_name $barcode
You have a hold available for pickup as of <%DATE%>:

Title: <%TITLE%>
Author: <%AUTHOR%>
Price: <%PRICE%>


             $cust_name
             <%CUST-ADDR%>
             <%CUST-CTY%>

end of file
TEMPLATE

用从stdin读取的行替换虚拟输入数组,可以使用(<>) (如果更有效率,可以使用一个循环读取n行并将其推入数组中)。我只展示了核心部分,根据需要添加更多变量,并通过为“capture”变量指定undef跳过输入行(如所示)。

现在,将这些变量简单地插入到您的文本中。

如果行末引起问题,请考虑使用chomp,例如:

my @lines = (<>); # just read em all...
my @cleaned = map { chomp } @lines;

在这个问题上,我稍微添加了一些关于如何继续前进的提示。 - sehe
模板部分需要从代码中移除,以便使其可重用于其他模板。我将处理这个问题。 - Bubnoff

0

这是我为这个项目使用的。欢迎提出改进建议,或者提交更好的解决方案。

cp $FILE $WORKING # we won't mess with original

NUM_RECORDS=$( grep "^Price:" "$FILE" | wc -l ) # need to know how many records we have 
                                              # counting occurences of end of record r

TMP=record.txt # holds single record, used as temp storage in loop below

# Sanity
# Make sure temp storage exists. If not create -- if so, clear it.
[ ! -f $TMP ] && touch $TMP || cat /dev/null >$TMP

# functions
function make_template () {
    local _file="$1"
    mapfile -t filecontent < "$_file"
    _loc_name="${filecontent[0]}"
    _loc_strt="${filecontent[1]}"
    _loc_city="${filecontent[2]}"
    _pat_name="${filecontent[14]}"
    _pat_addr="${filecontent[15]}"
    _pat_city="${filecontent[16]}"
    _barcode=${filecontent[27]:(-14)} # pull barcode from end of string
    _date=${filecontent[29]:(-11)}    # pull date from end of string
    # Test title length - truncate if necessary - 70 chars.
    _title=$(grep -E "^Title:" $_file)
    MAXLEN=70
    [ "${#_title}" -gt "$MAXLEN" ] && _title="${filecontent[31]:0:70}" || :
    _auth=$(grep -E "^Author:" $_file)
    _price=$(grep -E "^Price:" $_file)
    sed "
        s@<%BRANCH-NAME%>@${_loc_name}@g
        s@<%BRANCH-ADDR%>@${_loc_strt}@g
        s@<%BRANCH-CTY%>@${_loc_city}@g
        s@<%CUST-NAME%>@${_pat_name}@g
        s@<%CUST-ADDR%>@${_pat_addr}@
        s@<%CUST-CTY%>@${_pat_city}@
        s@<%BARCODE%>@${_barcode}@g
        s@<%DATE%>@${_date}@
        s@<%TITLE%>@${_title}@
        s@<%AUTHOR%>@${_auth}@
        s@<%PRICE%>@${_price}@" "$TEMPLATE"
}

####################################
#  MAIN
####################################

for((i=1;i<="$NUM_RECORDS";i++))
do
    sed -n '1,/^Price:/{p;}' "$WORKING" >"$TMP"  # copy first record with end of record
                                                # and copy to temp storage.

    sed -i '1,/^Price:/d' "$WORKING"             # delete first record using EOR regex.
    make_template "$TMP"                        # send temp file/record to template fu
done

# cleanup
exit 0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接