【问题标题】:header columns validation in shell scriptshell脚本中的标题列验证
【发布时间】:2021-12-11 09:04:33
【问题描述】:

“|”分隔文件应具有以下列标题

Activity
Activity+ ID
Description
Status

上传后,在开始使用 SQLLDR 处理文件之前,我确保上传的文件具有确切数量的标题,标题名称匹配且顺序相同。

代码:

declare -i header=4
fields=( 
"Activity"
"Activity+ ID"
"Description"
"Status"
)

for i in "Test File.csv"; do
    read -r line < "$i" 

    oldIFS="$IFS"
    IFS=$'|'
    fldarray=( $line );
    IFS="$oldIFS"

    nfields=${#fldarray[@]}     
    if (( nfields < header ))
    then
    printf "error: only '%d' fields in file '%s'\nmissing:" "$nfields" "$i"
    else        
        for item1 in "${header[@]}"; do
          for item2 in "${fields[@]}"; do
           if [[ $item1 != $item2 ]]; then
            Array3+=("$item1")
           fi
         done
        done
        echo "not matching" ${Array3[@]}
        printf "\n\n"
    fi
done

数据:

Activity|Activity+ ID|Description|Status
Test|1234|First activity|Open

这总是打印缺少 Activity+ 列,尽管它存在于文件中。从上传的标题和文件中删除“+”后,它按预期工作。 如何更改上述代码以使用“+”验证列标题。 我参考了bash to identify and verify file headers 的答案来构建这个解决方案

【问题讨论】:

  • 请显示文件文件的确切内容。 “应该有下面的列标题”,如果没有怎么办?还要检查你的行尾是否正常(dos2unix)。
  • 我刚刚在我的系统上运行了您的代码,并且没有报告“Activity+”丢失。但我不得不猜测输入文件的格式。请添加,以便我再次查看。
  • @Nic3500 更新了问题。确切的列名是“Activity+ ID”,我现在再次执行此操作并说“Activity+ ID”缺少列标题。
  • 标题可以按不同的顺序显示吗?快速而肮脏的解决方案是将第 1 行与固定字符串 Activity|Activity+ ID|Description|Status 进行比较。
  • @JeffSchaller 我不能这样做,因为我需要知道哪个列标题不匹配

标签: shell unix ksh


【解决方案1】:

注意:对于 OP 想要做什么仍然有点困惑(例如,header 被定义为整数,但后来被引用为数组 ("${header[@]}"))

假设:

  • 如果.csv 文件第一行中| 分隔字段的数量与fields[] 数组中的条目数量不匹配,则打印错误
  • .csv 文件中的标题字段必须与 fields[] 数组中的条目完全匹配(拼写和顺序)
  • 打印fields[] 数组中与| 文件第一行中的| 分隔字段不完全匹配的条目

我们将保留当前的fields[] 数组:

fields=("Activity" "Activity+ ID" "Description" "Status")

.csv文件的第一行拉入headers[]数组中:

IFS='|' read -r -a headers < test.csv      # read first line from test.csv, break on '|' delimiter, store in headers[] array

给我们:

$ typeset -p fields headers
declare -a fields=([0]="Activity" [1]="Activity+ ID" [2]="Description" [3]="Status")
declare -a headers=([0]="Activity" [1]="Activity+ ID" [2]="Description" [3]="Status")

现在对 OP 的if/else/for/fi 代码进行一些修改:

if [[ "${#fields[@]}" -ne "${#headers[@]}" ]]            # field count mismatch?
then
     echo "error: field count mismatch: expecting ${#fields[@]} / found ${#headers[@]}"
else
    Array3=()                                            # init array Array3[]

    for ((i=0;i<${#fields[@]};i++))                      # loop through indices of fields[] array
    do
        [[ "${fields[$i]}" != "${headers[$i]}" ]] && \   # if same position in both arrays is not a match then ...
        Array3+=("${fields[$i]}")                        # add fields[] entry to Array3[]
    done

    [[ "${#Array3[@]}" -ne 0 ]] && \                     # if Array3[] not empty then ...
    echo "not matching:" ${Array3[@]}                    # print list of fields to stdout
fi

对于这种特殊情况,${fields[@]}${headers[@]} 相同,不会生成任何输出。

其他测试用例:

headers[] 中的第二个字段拼写不同

declare -a fields=([0]="Activity" [1]="Activity+ ID" [2]="Description" [3]="Status")
declare -a headers=([0]="Activity" [1]="Activity+" [2]="Description" [3]="Status")

# the code generates:

not matching: Activity+ ID

headers[] 有 3 个条目

declare -a fields=([0]="Activity" [1]="Activity+ ID" [2]="Description" [3]="Status")
declare -a headers=([0]="Activity" [1]="Activity+ ID" [2]="Status")

# the code generates:

error: field count mismatch: expecting 4 / found 3

headers[] 有 4 个条目,但都与 fields[] 中的相应条目不同

declare -a fields=([0]="Activity" [1]="Activity+ ID" [2]="Description" [3]="Status")
declare -a headers=([0]="Activity+ ID" [1]="Description" [2]="Status" [3]="Activity")

# the code generates:

not matching: Activity Activity+ ID Description Status

从这里 OP 应该能够调整代码以提供所需的输出和/或设置一些变量以用于后续条件操作(例如,如果触发 echo,则中止处理,禁用后续处理如果 echo 被触发等)。

【讨论】:

  • 完美运行。太感谢了。由于某种原因,“+”值导致 if 循环出现问题,因此我将其替换为单词“PLUS”,然后进行比较,并在最终的不匹配返回值中将其替换回“+”。
  • 最后一个帮助,最后一个标题值表示虽然匹配但不匹配。可能是以回车或一些特殊字符结尾。所以之前 if "[[ "${fields[$i]}" != "${headers[$i]}" ]]" i added these 2 lines ${fields[$i]}=echo ${fields[$i]} | xargs echo -n; ${headers[$i]}=echo ${headers[$i]} | xargs echo -n 但仍然无法正常工作
  • 假设可见字符相同...尝试运行head -1 file | od -c 以查看该行中是否有任何非打印字符(例如,\r);还运行typeset -p &lt;array_name&gt; 并仔细检查每个数组条目的内容(例如,最后一个条目是否显示以\r 结尾?);如果您看到字符\r,最简单的解决方案是首先运行dos2unix &lt;filename&gt;(删除\r 字符),然后继续执行其余代码;如果您当时无法解决这个问题,我建议您提出一个新问题来解决这个新问题
  • 谢谢,最后有 \r 和 \n,被替换了,它按预期工作。
猜你喜欢
  • 2023-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多