【问题标题】:Iterate over a text file line by line within a for loop in a shell script在 shell 脚本的 for 循环中逐行迭代文本文件
【发布时间】:2020-09-03 19:40:09
【问题描述】:

我有一个看起来像这样的 txt 文件,名为 locations.txt

location-1a
location-2c
location-3d
location-4
location-5a
...

我希望在我的 for 循环中遍历 locations.txt 文件,每个位置应该用于 5 个节点,然后应该使用下一个位置。例如,我希望运行以下命令,

server create --location location-1a node-1
server create --location location-1a node-2
server create --location location-1a node-3
server create --location location-1a node-4
server create --location location-1a node-5
server create --location location-2c node-6

.....

到目前为止,我只有以下名为 script.sh 的脚本,它从 cli 中获取参数。我无法随意更改位置。

mapfile -t locationArr < ~/Documents/files/locations.txt
serverCounter=1
locationCounter=1
counter=1

counter=1
for (( i = 1; i <= $1; i++ ))
do
 server create --location $locationArr[$locationCounter] node-$i
 counter=$((counter+1))
 if [ $counter == 5 ]
 then
  counter=1
  locationCounter=$((locationCounter+1))
done

我想要类似的东西

if counter == 5:
 counter=0
 nextline 

例如,如果我运行script.sh 11,我想要以下结果,

server create --location location-1a node-1
server create --location location-1a node-2
server create --location location-1a node-3
server create --location location-1a node-4
server create --location location-1a node-5
server create --location location-2c node-6
server create --location location-2c node-7
server create --location location-2c node-8
server create --location location-2c node-9
server create --location location-2c node-10
server create --location location-3d node-11

如何在我的 for 循环中遍历 location.txt 文件?我应该将文本文件转换为某种列表变量吗?

【问题讨论】:

标签: bash shell loops


【解决方案1】:

这是我的尝试:

counter=1
while IFS= read -r line
do
    for (( i=1; i <= 5 && $counter <= $1; i++ ))
    do
     server create --location $line node-$counter
     counter=$((counter+1))
    done 
done < ~/Documents/files/locations.txt

11 的输出:

server create --location location-1a node-1
server create --location location-1a node-2
server create --location location-1a node-3
server create --location location-1a node-4
server create --location location-1a node-5
server create --location location-2c node-6
server create --location location-2c node-7
server create --location location-2c node-8
server create --location location-2c node-9
server create --location location-2c node-10
server create --location location-3d node-11

【讨论】:

  • 我猜应该是node-"$counter",但这个问题在这一点上有点令人困惑。
  • 是的,我现在意识到了这一点。我的输出与 OP 问题不匹配。
  • 我想我现在得到了他想要的。
  • 嘿,i &lt;= 5 &amp;&amp; $counter &lt;= $1 部分是如何工作的?它如何进入while循环中的下一行?
  • 对于文件中的每一行。它会在所有有效的 i 上循环,从 1 到 5。为了进行这个迭代,它还必须满足 counter 仍然小于提供的命令行值的条件。我现在看到一个问题,即使count 超出$1 但不会吐出任何输出,它也会继续读取输入文件。如果这是一个问题,一旦满足此条件,您可以在内部 for 循环之后使用 break 以停止读取输入文件。如果不清楚,请告诉我。
【解决方案2】:

总纲:

  • locations.txt读取位置的外循环
  • 用于为给定位置生成最多 5 个节点的内部循环
  • 每次生成一个节点时都会增加一个计数
  • 如果计数器 > 输入 'max' 然后跳出循环

上述的一种实现:

max=${1}
curr=1

while read -r location
do
    for i in {1..5}
    do
        echo "server create --location ${location} node-${curr}"
        curr=$((curr+1))
        [ ${curr} -gt ${max} ] && break 2
    done
done < locations.txt

使用max=${1}=11 测试运行:

server create --location location-1a node-1
server create --location location-1a node-2
server create --location location-1a node-3
server create --location location-1a node-4
server create --location location-1a node-5
server create --location location-2c node-6
server create --location location-2c node-7
server create --location location-2c node-8
server create --location location-2c node-9
server create --location location-2c node-10
server create --location location-3d node-11

OP 可以添加额外检查 max 是否为大于 0 的整数。

【讨论】:

  • 不错!我喜欢break 2 .. 我完全忘记了这个结构。
【解决方案3】:

用单循环完成,没有 Bashism POSIX 语法:

#!/usr/bin/env sh

i=0
while [ $i -lt "$1" ] && {
  [ $((i % 5)) -ne 0 ] || IFS= read -r line || [ "$line" ]
}; do
  server create --location "$line" "node-$((i = i + 1))"
done <locations.txt

【讨论】:

  • 很好,但您可能需要将输出限制为命令行值$1 而不是位置.txt 的结尾
  • 您的解决方案继续为locations.txt 中的所有行生成输出。从 OP 样本输出来看,输出需要在达到给定限制时停止,$1
  • 太棒了...我有一个问题,|| [ "$line" ] 到底是做什么的?没有它似乎也能正常工作。是为了避免locations.txt中的空行吗?
  • @hesham_EE 如果最后一行不以newline 字符结尾,则返回true。否则最后一个read 会导致条件失败,最后一行不会被处理。
猜你喜欢
  • 1970-01-01
  • 2015-08-20
  • 1970-01-01
  • 2017-08-25
  • 2013-10-04
  • 2022-05-17
  • 2011-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多