很棒的小练习。虽然我可能倾向于awk 解决方案,但在 bash 中,您还可以依靠 使用子字符串替换的参数扩展 来替换每个 mthnth 字段/em> 行。本质上,您可以读取每一行,保留空格,然后检查您的行数,例如如果c 是您的行计数器,m 是您的变量mth 行,您可以使用:
if (( $((c % m )) == 0)) ## test for mth line
如果该行是替换行,您可以在恢复默认分词后将每个单词读入一个数组,然后使用您的数组元素索引n-1 来提供替换(例如${line/find/replace} 和${line/"${array[$((n-1))]}"/replace})。
如果它不是替换行,只需输出该行不变。一个简短的示例可能类似于以下内容(您可以根据需要添加其他验证)
#!/bin/bash
[ -n "$1" -a -r "$1" ] || { ## filename given an readable
printf "error: insufficient or unreadable input.\n"
exit 1
}
n=${2:-1} ## variables with default n=1, m=3, e=wot
m=${3:-3}
e=${4:-wot}
c=1 ## line count
while IFS= read -r line; do
if (( $((c % m )) == 0)) ## test for mth line
then
IFS=$' \t\n'
a=( $line ) ## split into array
IFS=
echo "${line/"${a[$((n-1))]}"/$e}" ## nth replaced with e
else
echo "$line" ## otherwise just output line
fi
((c++)) ## advance counter
done <"$1"
使用/输出示例
n=1、m=3、e=wot
$ bash replmn.sh dat/repl.txt
foo 1 6 0
fam 5 11 3
wot 7 23 8
woo 2 8 4
kaz 6 4 9
wot 5 8 8
n=1、m=2、e=baz
$ bash replmn.sh dat/repl.txt 1 2 baz
foo 1 6 0
baz 5 11 3
wam 7 23 8
baz 2 8 4
kaz 6 4 9
baz 5 8 8
n=3、m=2、e=99
$ bash replmn.sh dat/repl.txt 3 2 99
foo 1 6 0
fam 5 99 3
wam 7 23 8
woo 2 99 4
kaz 6 4 9
faz 5 99 8
awk 解决方案更短(并且避免了在$line 中重复出现替换字符串的问题),但两者都需要类似的字段存在验证等。从两者中学习并告诉我你是否有任何问题。