基于Bash中的列值过滤行
问题描述:
我有一个bash脚本输出一些基于列的信息。我想给用户一些匹配值的选项是特定的列。例如,./myColumnDump
可能会打印基于Bash中的列值过滤行
User Job_name Start_day andrew job1_id monday andrew job2_id tuesday adam job1_id tuesday adam job2_id monday
,我想补充像./myColumDump -j 2
选项(其中的J的说法是使用正则表达式匹配,其在JOB_NAME列中的值)。
我目前正在通过grep管道输出,并将用户指定的正则表达式嵌入到一个大正则表达式中以匹配整行,但是他/她可能会指定-j .*monday
这将溢出到不同的列中。
有没有更好的方法来实现这个在bash脚本?
答
下面是完整的bash脚本scan.sh做你的工作:
#!/bin/bash
usage()
{
cat << EOF
usage: $0 options
This script scans given input file for specified regex in the input column #
OPTIONS:
-h Show usage instructions
-f input data file name
-r regular expression to match
-j column number
EOF
}
# process inputs to the script
DATA_FILE=
COL_NUM=
REG_EX=
while getopts ":j:f:r:h" OPTION
do
case $OPTION in
f) DATA_FILE="$OPTARG" ;;
r) REG_EX="$OPTARG" ;;
j) COL_NUM="$OPTARG" ;;
\?) usage
exit 1 ;;
h)
usage
exit 1 ;;
esac
done
if [[ -z $DATA_FILE ]] || [[ -z $COL_NUM ]] || [[ -z $REG_EX ]]
then
usage
exit 1
fi
awk -v J=${COL_NUM} -v R="${REG_EX}" '{if (match($J, R)) print $0;}' "${DATA_FILE}"
测试
比方说,这是你的数据文件: 用户JOB_NAME START_DAY
andrew job1_id monday
andrew job2_id tuesday
adam job1_id tuesday
adam job2_id monday
./scan.sh -j 2 -f data -r ".*job1.*"
andrew job1_id monday
adam job1_id tuesday
./scan.sh -j 2 -f data -r ".*job2.*"
andrew job2_id monday
adam job2_id tuesday
./scan.sh -j 1 -f data -r ".*adam.*"
adam job1_id tuesday
adam job2_id monday
答
此问题是为awk(1)量身定做的。例如,您可以执行以下操作:
awk '$2 ~ /^job1/'
可打印出第2列匹配的行^job1
。因此,鉴于N
列数和R
正则表达式,你应该能够做到这一点:
awk "\$${N} ~ /${R}/"
你会像往常一样,需要小心你的报价。
答
要建立在亩太短的回答,您可以将用户的模式传递给AWK:
# suppose the -j pattern is in shell var $j
awk -v j="$j" '$2 ~ j'
不得不提醒用户输入了awk理解虽然正则表达式。
答
这里的一个纯粹的bash脚本(礼貌anubhava)
#!/bin/bash
# tested on bash 4
usage()
{
cat << EOF
usage: $0 options [file]
This script scans given input file for specified regex in the input column #
OPTIONS:
-h Show usage instructions
-f input data file name
-r regular expression to match
-j column number
Example: $0 -j 2 -r "job2" -f file
EOF
}
# process inputs to the script
DATA_FILE=
COL_NUM=
REG_EX=
while getopts ":j:f:r:h" OPTION
do
case $OPTION in
f) DATA_FILE="$OPTARG" ;;
r) REG_EX="$OPTARG" ;;
j) COL_NUM="$OPTARG" ;;
\?) usage
exit 1 ;;
h)
usage
exit 1 ;;
esac
done
if [[ -z $DATA_FILE ]] || [[ -z $COL_NUM ]] || [[ -z $REG_EX ]]
then
usage
exit 1
fi
while read -r line
do
array=($line)
col=${array[$((COL_NUM-1))]}
[[ $col =~ $REG_EX ]] && echo "$line"
done < $DATA_FILE