将文本从固定长度字段转换为json时出现问题

将文本从固定长度字段转换为json时出现问题,json,bash,awk,jq,Json,Bash,Awk,Jq,我有一个有效的解决方案,它从客户机sftp服务器下载一个压缩的固定长度字段文本文件,使用密码解压,然后在该文件上运行gnu awk,将其转换为管道分隔的文本文件,然后自我清理 Bash脚本代码如下: #!/bin/bash export ZipPassword=******** export SSHPASS=******** export WorkPath=/Users/administrator/Documents/Work/ export ArcPath=/Users/administrat

我有一个有效的解决方案,它从客户机sftp服务器下载一个压缩的固定长度字段文本文件,使用密码解压,然后在该文件上运行gnu awk,将其转换为管道分隔的文本文件,然后自我清理

Bash脚本代码如下:

#!/bin/bash
export ZipPassword=********
export SSHPASS=********
export WorkPath=/Users/administrator/Documents/Work/
export ArcPath=/Users/administrator/Documents/Work/archive/
export DownPath=/Users/administrator/Documents/Work/down/
export InPath=/Users/administrator/Documents/Work/input/
export ReadyPath=/Users/administrator/Documents/Work/preproc/
export OutPath=/Users/administrator/Documents/Work/Output/
export AwkPath=/Users/administrator/Documents/Work/scpost.awk


cd $DownPath

sshpass -e sftp -oBatchMode=no -b - ****@*****.*******.*** << !
    cd /frommbi
    get *.zip
    rm *.zip
    exit
!


for f in *.zip
do 
    cp -v "$f" "$InPath"
    cp -v "$f" "$ArcPath"
    rm *.zip
done    

shopt -s nullglob dotglob     # To include hidden files
files=($InPath*)
if [ ${#files[@]} -gt 0 ]; then


unzip -P $ZipPassword $InPath*.zip -d $ReadyPath


for f in $ReadyPath
do
    export PathName=/Users/administrator/Documents/Work/PreProc/*.TXT
    echo $PathName
    export FileName=`basename $PathName`
    echo $FileName
    echo $OutPath$FileName

awk -f $AwkPath $PathName > $OutPath$FileName

done



rm -f $InPath*
rm -f $ReadyPath*

fi
awk文件内容如下:

BEGIN{FIELDWIDTHS=" 3 2 2 18 5 9 10 10 10 14 16 30 30 30 30 30 30 30 30 45 45 45 45 45 45 45 45 16 28 6 1 1 3 2 6 2 4 3 2 30 3 3 3 40 6 5 6 3 3 3 40 6 5 6 3 3 3 40 6 5 6 3 3 3 40 6 5 6 3 3 3 40 6 5 6 3 3 3 40 6 5 6 3 3 3 40 6 5 6 3 3 3 40 6 5 6 20 7 20 2 6 13 6 6 6 32 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 40 2 6 20 30 11 12 3 1 14 14 1 4 4 4 4 4 4 4 12 28 30 8 2 1 8 8 8 8 8 10 12 8 130 1 7 65 3 82 512 528 1 "; 
OFS="|";
}
{
for (i=1;i<=NF;i++) gsub (/^ */,"",$i);for(i=1;i<=NF;i++) gsub("^[ \t]*|[ \t]*$","",$i);
}
{
print$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$60,$61,$62,$63,$64,$65,$66,$67,$68,$69,$70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$80,$81,$82,$83,$84,$85,$86,$87,$88,$89,$90,$91,$92,$93,$94,$95,$96,$97,$98,$99,$100,$101,$102,$103,$104,$105,$106,$107,$108,$109,$110,$111,$112,$113,$114,$115,$116,$117,$118,$119,$120,$121,$122,$123,$124,$125,$126,$127,$128,$129,$130,$131,$132,$133,$134,$135,$136,$137,$138,$139,$140,$141,$142,$143,$144,$145,$146,$147,$148,$149,$150,$151,$152,$153,$154,$155,$156,$157,$158,$159,$160,$161,$162,$163,$164,$165,$166,$167,$168,$169,$170,$171
}
请注意,此处的字段名是数字,以便以后在数据库中启用映射

我已经安装了jq来处理从管道分隔数据到json的转换,但是我还不能获得正确的语法

修改后的bash脚本内容见第52-56行:

#!/bin/bash
export ZipPassword=********
export SSHPASS=********
export WorkPath=/Users/administrator/Documents/Work/
export ArcPath=/Users/administrator/Documents/Work/archive/
export DownPath=/Users/administrator/Documents/Work/down/
export InPath=/Users/administrator/Documents/Work/input/
export ReadyPath=/Users/administrator/Documents/Work/preproc/
export OutPath=/Users/administrator/Documents/Work/Output/
export AwkPath=/Users/administrator/Documents/Work/scpost.awk
export JsonPath=/Users/administrator/Documents/Work/JSON/


cd $DownPath

sshpass -e sftp -oBatchMode=no -b - ****@*****.*******.*** << !
    cd /frommbi
    get *.zip
    rm *.zip
    exit
!


for f in *.zip
do 
    cp -v "$f" "$InPath"
    cp -v "$f" "$ArcPath"
    rm *.zip
done    

shopt -s nullglob dotglob     # To include hidden files
files=($InPath*)
if [ ${#files[@]} -gt 0 ]; then


unzip -P $ZipPassword $InPath*.zip -d $ReadyPath


for f in $ReadyPath
do
    export PathName=/Users/administrator/Documents/Work/PreProc/*.TXT
    echo $PathName
    export FileName=`basename $PathName`
    echo $FileName
    echo $OutPath$FileName

awk -f $AwkPath $PathName > $OutPath$FileName

done
chmod 776 $OutPath$FileName

jq -Rn  --slurp --raw-input --raw-output \'
( input  | split("|") ) as $keys |
( inputs | split("|") ) as $vals |
[[$keys, $vals] | transpose[] | {key:.[0],value:.[1]}] | from_entries
' $OutPath$FileName > $JsonPath$FileName



rm -f $InPath*
rm -f $ReadyPath*
rm -f $JsonPath*


fi

有人能帮忙吗?在你提问之前,我使用这种方法是为了提高转换速度。我的Mac Pro可以在大约20秒内转换100000条2850个字符的记录,并且每天都可以转换。转换为json将大大加快这一过程的下一步。

您就快到了。因为您使用的是输入和输入,这在这里绝对是正确的方法,所以您不想使文件变得含糊不清

jq  -nrR '
 ( input  | split("|") ) as $keys
 | ( inputs | split("|") ) as $vals
 | [[$keys, $vals] | transpose[] | {key:.[0], value:.[1]|tonumber}]
 | from_entries
'
顺便说一下,您可以轻松地将awk+jq步骤组合成一个awk或一个jq步骤。这样做可以节省大量不必要的咀嚼。如果你选择坚持awk,我会把重点放在缩短1美元、2美元、1美元、1美元、1美元、1美元、1美元、2美元、1美元、1美元、1美元、1美元、1美元、1美元、1美元、1美元、1美元、1美元、2美元、1美元、1美元、2美元、1美元、2。。。陈述打印$0不够吗

awk的场宽当然很方便,因此在下一节中,将介绍一个jq滤波器,用于根据输入字符串和关于场宽的信息发射阵列

使用jq解析固定长度字段 如果jq没有foreach,这里有一个替代实现:

def fixedfields(widths):
  def do_while(cond; f; g): def r: select(cond) | f | (g, r); r;
  {s:., w: widths}
  | do_while(.w|length > 0;
             .w[0] as $w | {s: .s[$w:], w: .w[1:], field: .s[:$w] };
             .field);

如果问题出在jq中,最好删除其余脚本,只向jq提供输入和预期输出。问题可能根本不是jq。最好的解决方案可能是对awk文件进行不同的编码,并在不使用中间格式的情况下将固定长度字段转换为json。也许我应该包括我对其他解决方案持开放态度。顶部的代码生成了一个我似乎无法解决的错误:jq:error at/Users/administrator/Documents/Work/Output/pcycle219103821.TXT:2:EOF第1行第2列解析“C$”时无效的数值文本
def fixedfields(widths):
  def do_while(cond; f; g): def r: select(cond) | f | (g, r); r;
  {s:., w: widths}
  | do_while(.w|length > 0;
             .w[0] as $w | {s: .s[$w:], w: .w[1:], field: .s[:$w] };
             .field);