我的输入文件是行长度可变的单列。我的代码应该计算这些行,并打印指定的数字。我遇到的问题是,如果变量“A”中捕获的行数小于 1,我希望它至少打印 1 行,以便输出文件不为空。如果“A”(总行数的 1%)大于 1,我想打印该行数。我的混合 awk-bash 代码如下所示:
#!/bin/sh
for i in {1..2}
do
input="../ExpressionSet_"$i"_chunk.txt"
for j in {1..2}
do
A=$(awk 'END{print NR*0.01}' $input)
Y=1
X=0
if (( "$A" -lt "$Y")); then
X=$A+1
else
X=$A
fi
awk 'NR<='$X' {print $0}' $input > "$i"_top1pc.txt
B=$(awk 'END{print NR*0.05}' $input)
awk 'NR<='$B' {print $0}' $input > "$i"_top5pc.txt
令人困惑的是,我不断收到类似的错误消息
thresholdSelector_pc.sh: line 20: ((: 0.24 -lt 1: syntax error: invalid arithmetic operator (error token is ".24 -lt 1")
thresholdSelector_pc.sh: line 20: ((: 47.24 -lt 1: syntax error: invalid arithmetic operator (error token is ".24 -lt 1")
顺便说一句,inputFile1有24行,inputFile2有4724行。谢谢您的帮助!
答案1
我认为你的根本问题是你试图在 sh 脚本中使用 bash 语法。 Bash 定义了 sh 公分母的扩展;如果您想使用 bash 特定的功能,您的脚本必须以 开头#!/bin/bash
,而不是#!/bin/sh
。
Sh 没有((…))
算术表达式的语法。但这里不需要它,您可以使用可移植的[ … ]
条件语法。在[ … ]
条件句中,写有“小于”运算符-lt
。
大括号{1..2}
是 sh 中不存在的另一个 bash 功能。脚本中的另一个错误是X=$A+1
,它设置X
为一个字符串,就像42+1
if 的值A
是42
;要执行算术计算,您需要使用算术表达式语法$((…))
。
另外,作为一般性评论,始终在变量替换周围使用双引号。
您的代码的另一个问题是它看起来像是A
一个十进制数。 Shell 算术仅适用于整数。我已经调整了算法,但检查了它的作用,我可能没有按照您想要的方式进行舍入。仅使用 awk 来计算行数就有点过分了,wc -l
这是一种更清晰、更快的方法。同样,要打印文件的前 N 行,只需调用head
.
另一个错误是$i_chunk
变量的值i_chunk
。要获取i
并追加的值_chunk
,您需要用大括号分隔变量名称:${i}_chunk
。
我不知道循环j
应该做什么,我没有管它。
#!/bin/sh
for i in 1 2
do
input="../ExpressionSet_${i}_chunk.txt"
for j in 1 2
do
A=$(wc -l <"$input")
Y=100
X=0
if [ "$A" -lt "$Y" ]; then
X=$((A+100))
else
X=$A
fi
head -n "$((X/100))" "$input" > "$i"_top1pc.txt
head -n "$((X/20))" "$input" > "$i"_top5pc.txt
done
done
如果您选择编写 bash 脚本,则可以利用多个 bash 功能:
((…))
用于算术评估(但仍然仅限整数)typeset -i
声明一个整型变量,以便分配一个算术表达式来计算它
#!/bin/bash
for i in 1 2
do
input="../ExpressionSet_${i}_chunk.txt"
for j in 1 2
do
A=$(wc -l <"$input")
Y=100
typeset -i X
if ((A < Y)); then
X=A+100
else
X=$A
fi
head -n "$((X/100))" "$input" > "$i"_top1pc.txt
head -n "$((X/20))" "$input" > "$i"_top5pc.txt
done
done