Hello Stackoverflow社区,
请原谅我的想法,但是我有一个基本的循环脚本,它运行着一个更复杂的脚本,该脚本正在寻找文本文件以作为数组输入。我想它可以正常工作,但是我知道它可以更好,更自动化地运行。
这是脚本要查找的文本文件;
2014;14204;
2015;15042;
2015;15062;
...
end;
这是我作为循环运行的bash脚本;
{ while IFS=';' read YEAR1 PROJ1 YEAR2 PROJ2 YEAR3 PROJ3 fake
do
{ echo "$YEAR1" | egrep '^#|^ *$' ; } > /dev/null && continue
$local/script.sh \
--forinput1 $YEAR1/$PROJ1 \
--forinput2 $YEAR2/$PROJ2 \
--forinput3 $YEAR3/$PROJ3 \
done
} < textFile.txt
我自己进行了一些研究,发现了一些我认为可以解决的问题,但未能正确实施。如果您能给我一些指导,我将不胜感激。
编辑: 我确实表示歉意,因此脚本确实将文本文件识别为:
YEAR1;PROJ1;
YEAR2;PROJ2;
YEAR3;PROJ3;
使用“;”作为其分隔符。它确实会循环运行,直到完成最后一个变量。但是,要实现此功能,我需要在文本文件中添加额外的行
YEAR4;PROJ4;
YEAR5;PROJ5;
end;
然后添加脚本
{ while IFS=';' read YEAR1 PROJ1 YEAR2 PROJ2 YEAR3 PROJ3 YEAR4 PROJ4 YEAR5 PROJ5 fake
do
{ echo "$YEAR1" | egrep '^#|^ *$' ; } > /dev/null && continue
$local/script.sh \
--forinput1 $YEAR1/$PROJ1 \
--forinput2 $YEAR2/$PROJ2 \
--forinput3 $YEAR3/$PROJ3 \
--forinput4 $YEAR4/$PROJ4 \
--forinput5 $YEAR5/$PROJ5 \
done
} < textFile.txt
我希望完成的是在数组中添加变量,而不必在脚本中添加额外的语法
这很坏,但我想我正在寻找的是
{ while IFS=';' read -a YEAR PROJ < textFile.txt
for ((i = 0; i < "${#YEAR[@]};${#PROJ[@]}"; i++)); do
{ echo "$YEAR[$i]" | egrep '^#|^ *$' ; } > /dev/null && continue
$local/script.sh \
--forinput[$i] ${YEAR[$i]}/${PROJ[$i]} \
done
}
答案 0 :(得分:0)
我假设您的输入文件包含3行的组,每行2个字段,而不是6个字段的行。
$ cat file
y1a;p1a;
y2a;p2a;
y3a;p3a;
y1b;p1b;
y2b;p2b;
y3b;p3b;
然后,您可以将多个读取命令作为while“ condition”:
while
IFS=';' read year1 proj1 x
IFS=';' read year2 proj2 x
IFS=';' read year3 proj3 x
do
echo script \
--forinput1 "$year1/$proj1" \
--forinput2 "$year2/$proj2" \
--forinput3 "$year3/$proj3"
done < file
script --forinput1 y1a/p1a --forinput2 y2a/p2a --forinput3 y3a/p3a
script --forinput1 y1b/p1b --forinput2 y2b/p2b --forinput3 y3b/p3b
但是,这不能处理注释和空白行。此版本在第三行非(注释/空白)行之后执行脚本
$ cat file
# set 1
y1a;p1a;
y2a;p2a;
y3a;p3a;
# set 2
y1b;p1b;
y2b;p2b;
y3b;p3b;
和
n=0
args=()
while IFS=';' read year project x; do
{ [[ $year == *([[:blank:]])"#"* ]] || [[ $year == *([[:blank:]]) ]]; } && continue
((n++))
args+=( "--forinput$n" "$year/$project" )
if (( n == 3 )); then
echo script "${args[@]}"
args=()
n=0
fi
done < file
script --forinput1 y1a/p1a --forinput2 y2a/p2a --forinput3 y3a/p3a
script --forinput1 y1b/p1b --forinput2 y2b/p2b --forinput3 y3b/p3b
另一种处理每组任意记录的方法:
$ cat file
# set 1
y1a;p1a;
y2a;p2a;
y3a;p3a;
y4a;p4a;
y5a;p5a;
end;
# set 2
y1b;p1b;
y2b;p2b;
y3b;p3b;
end;
$ grep -Pv '^\s*(#|$)' file | awk -F"\n" -v RS="\nend;\n" -v OFS=, '{
cmd = "script.sh"
for (i=1; i<=NF; i++) {
n = split($i, a, /;/)
cmd = sprintf( "%s --forinput%d \"%s/%s\"", cmd, i, a[1], a[2])
}
print cmd
}'
script.sh --forinput1 "y1a/p1a" --forinput2 "y2a/p2a" --forinput3 "y3a/p3a" --forinput4 "y4a/p4a" --forinput5 "y5a/p5a"
script.sh --forinput1 "y1b/p1b" --forinput2 "y2b/p2b" --forinput3 "y3b/p3b"
使用grep
过滤掉注释和空白行。然后awk
来格式化命令:
RS
是记录分隔符,使用end;
行-F"\n"
将字段分隔符设置为换行符NF
)来构造要运行的命令,并将其打印出来。要实际执行它,请将awk输出通过管道传递到| sh
答案 1 :(得分:0)
您的代码建议每个输入行都有6个字段,这可能导致类似的代码
sed -nr 's#([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);([^;]*);#$local/script.sh --forinput \1/\2 --forinput \3/\4 --forinput \5/\6#p' textFile.txt
# or shorter
f='([^;]*;)'
sed -nr 's#'$f$f$f$f$f$f'#$local/script.sh --forinput \1/\2 --forinput \3/\4 --forinput \5/\6#p' textFile.txt
当您必须将三行输入结合在一起时,您不应该变得聪明。
# Don't do this
cat textFile.txt | paste -d'X' - - - | tr -d 'X'
# Trying to make
sed -nr 's#'$f$f$f$f$f$f'#$local/script.sh --forinput \1/\2 --forinput \3/\4 --forinput \5/\6#p' <(cat textFile.txt | paste -d'X' - - - | tr -d 'X')
自豪地展示代码后,您会发现当第二行是注释(以'#'开头)时,您将不得不使代码变得更糟。您需要将cat textFile.txt
替换为grep -Ev '^#|^ *$' testFile.txt
。
当您需要关联不同的行时,请查看awk
。
没有检查的解决方案是
awk -F';' '{line++}
{param=param " --forinput " $1 "/" $2}
line==3 {print "$local/script.sh" param ; param=""; line=0}
' textFile.txt
您可以添加各种检查。