从一个文件读取一个文件到一个数组在bash中的迭代
我想写一个小的脚本,将采取文件的第4列并将其存储在一个数组中,然后做一个比较。如果数组中的元素大于0且小于500,我必须增加计数器。然而,当我运行该脚本计数器始终显示为0。这里是我的脚本从一个文件读取一个文件到一个数组在bash中的迭代
#!/bin/bash
mapfile -t my_array < <(cat file1.txt | awk '{ print $4 }' > test.txt)
COUNTER=0
for i in ${my_array[@]}; do
if [["${my_array[$i]}" -gt 0 -a "${my_array[$i]}" -lt 500 ]]
then
COUNTER=$((COUNTER + 1))
fi
printf "%s\t%s\n" "%i" "${my_array[$i]}"//just to test if the mapfile command is working
done
echo $COUNTER
输出:
./script1.bash
0
#!/bin/bash
mapfile -t my_array < <(awk '{ print $4 }' file1.txt | tee test.txt)
COUNTER=0
for idx in "${!my_array[@]}"; do
value=${my_array[$idx]}
if ((value > 0)) && ((value < 500)); then
COUNTER=$((COUNTER + 1))
fi
printf "%s\t%s\n" "$idx" "$value"
done
echo "$COUNTER"
- 使用的
cat
这里不用:它补充什么,但效率低下(需要启动额外的进程,并强制awk从管道中读取而不是直接从文件中读取)。 -
mapfile
没有什么可读的,因为awk
的输出被重定向到test.txt
。如果你想把它同时转到文件和 stdout,那么你需要使用tee
。 -
-a
在[[ ]]
中无效;改为使用&&
。但是,由于您只做算术,所以(())
更合适。顺便提一下,即使对于[ ]
和test
,-a
也被正式标记为过时;见the current POSIX standard。 -
${my_array[@]}
重复值。如果您要遍历索引,则需要改为${!my_array[@]}
。 - 空格在分隔命令名称时是必需的。
[["$foo"
是与[[
不同的命令,除非$foo
为空或以$ IFS中的字符开头。
如果不需要'test.txt',那么mapfile可以写成mapfile -t my_array codeforester
令人惊讶的是'shellcheck'没有捕获到'-a在[[]]'部分无效。应该抓住它! – Inian
@Inian是的,抓到它,但前提是其他的一些问题是固定的,看到https://github.com/koalaman/shellcheck/wiki/SC2108 –
如果您将输出重定向到一个文件:> test.txt
那么在“标准输出”中没有输出,因为它被文件占用。所以,首先,你需要删除重定向。您可以使用:
mapfile -t my_array < <(cat file1.txt | awk '{ print $4 }')
但由于AWK可以非常清楚读取的文件,这是更好的:
mapfile -t my_array < <(awk '{ print $4 }' file1.txt)
而且,由于您使用的awk,它可以做的比较为0和500,并输出整个计数。
counter=$(awk '{if($4>0 && $4<500){c++}}END{print c}' file1.txt)
echo "$counter"
更简单,更快。
这也将避免一些简单的错误,在你的脚本,就像在[…]
结构缺少空间:
if [[ "${my … # NOT "if [["${my …"
而且缺少一些报价:
for i in "${my_array[@]}" # NOT for i in ${my_array[@]}
在一般情况下,这是一个很好想法检查您的脚本与ShellCheck.net删除一些简单的错误。
支持这一点可以全部在awk的一行中完成。 –
''[''后面需要空格。另外,因为'awk'输出将转到'test.txt',所以你可能不会在'my_array'中得到任何东西。 – codeforester
双引号数组下标,'因为我在“$ {my_array [@]}”;' – Inian
请通过http://shellcheck.net/运行代码,并修复它发问这里之前耳目一新的习惯。 –