我有一个循环将一些行添加到配置文件中:
for i in ${H//,/ }
do
sed -i "7i\ host($i) or" $configPath/$g.conf
done
$H 是逗号分隔的变量,例如:host1,host2,host4,host10
它返回以下内容:
host(host10) or host(host4) or host(host2) or host(host1) or
但我想要实现的是:
host(host10) or host(host4) or host(host2) or host(host1)
或相反亦然:
host(host1) or host(host2) or host(host4) or host(host10)
谁能帮助我找到正确的方向,我怎样才能做到这一点?
答案1
这个问题在大多数编程语言中都以相同的形式出现。以某种方式跳过后缀会很复杂。我不会讨论 shell 语法,只是用伪代码概述人们通常处理这个问题的方式:
# get it over with at the beginning:
print a[0] (no newline)
loop from a[1] onwards:
print "or\n"
print a[i]
print "\n" #terminate the last one
这种情况可以通过循环索引或仅循环所有元素(跳过第一个)来工作,因为不涉及索引测试(如果语言支持对数组的直接迭代,例如 bash 和 python)。
你也可以从0开始,跳过最后一个,在循环外处理(上面的镜像),但是跳过最后一个通常比较脏,而且可能是不可能的(要跳过最后一个,你必须知道它是最后一个,但第一个总是可以立即跳过)。例如,如果您正在从流中读取元素,您无法提前知道哪一个是最后一个,而这种形式是唯一的选择!
另一种方式:
# test a loop counter
N = length of array
loop with indices:
if i==N-1:
print a[i]
else:
print a[i],"or"
请注意,这种情况需要您知道有多少个元素,并且它会不断测试索引。因此,您必须循环索引,或者单独跟踪索引(在循环之前设置 i=0,在循环内部设置 i++)。
我把这个写成一个菜谱,我将把 bash 的实现留给你。
答案2
从我看来,您只需要对代码进行一些细微的更改:只需将“或”放入第一个循环期间为空的变量中即可。
operator=''
for i in ${H//,/ }
do
sed -i "7i\ host($i)$operator" "$configPath/$g.conf"
operator=' or'
done
答案3
您通常不想使用 shell 循环来进行文本处理。在这里,我会使用awk
:
export H
awk 'NR == 7 {
s = ENVIRON["H"]
gsub(/,/, ") or\n host(", s)
print " host(" s ")"}
{print}' file
就像 GNUsed
具有-i
就地编辑选项一样,GNU awk
(自 4.1.0 起)也具有-i /usr/share/awk/inplace.awk
1 作为等效选项。
如果您想编辑文本文件,有人可能会认为您应该使用文本编辑器。使用vim
,您可以通过以下方式实现相同的方法:
export H
vim -esc '
let @a=$H
6put a
s/.*/host(&)/
s/,/) or\rhost(/g
x' file
^不使用-i inplace
as尝试首先从当前工作目录gawk
加载inplace
扩展(asinplace
或),有人可能已经在其中植入了恶意软件。随系统提供的扩展inplace.awk
的路径可能会有所不同,请参阅输出inplace
gawk
gawk 'BEGIN{print ENVIRON["AWKPATH"]}'
答案4
我没有使用原始问题中的“sed”,而是编写了一个带有 echo 的更简单的问题来说明这一想法:而不是循环遍历空格分隔的项目:
- 首先我们得到“,”替换后的字数来确定迭代次数
- 使用“()”将空白字符串转换为数组
- 迭代计数
- 将“或”部分作为条件的输出并放入变量中
- 通过迭代对数组进行子集化
还有 echo/sed 等
#!/bin/bash H="host1,host2,host3" H2=${H//,/ } N=`echo $H2 | wc -w` H3=($H2) for ((i = 1; i <= $N; i++)) do if [ "$i" -eq "$N" ]; then OR=""; else OR=" or"; fi ITEM=${H3[$i-1]} echo "$ITEM$OR" done