【问题标题】:Replace nested for loops in bash替换 bash 中的嵌套 for 循环
【发布时间】:2021-01-22 09:50:52
【问题描述】:

你能帮我摆脱嵌套的 for 循环吗? 数组可能一直在变化,截至目前我需要添加/删除 for 循环。纯 bash 是否可以用更优雅的解决方案替换嵌套的 for 循环?

#!/bin/bash

i=0
array=(A B C)
places=3
word1=word1
word2=word2
arrC=${#array[*]}
while [ $i -lt $((arrC**places)) ]; do
    for a in ${!array[*]}; do
        for b in ${!array[*]}; do
            for c in ${!array[*]}; do
                echo "[$i] ${array[$a]}${word1}${array[$b]}${word2}${array[$c]}"
                i=$((i + 1))
            done
        done
    done
done

为简单起见,我制作了 ABC 数组。这是一个数组的更多真实示例: 数组=(I i L l | \ / 1 !)

【问题讨论】:

  • ????您想在一个循环中处理 a/b/c 的所有组合吗?为什么?
  • 代码试图做什么?
  • 这可能很愚蠢,但有时我得到的密码写得不好,这是通过三手在纸上完成的。自己检查比得到答案要快。除此之外,有时制作这些密码的人并不记得他们自己写了什么。并且要重新制作它们需要额外的成本和时间。
  • 可以使用 GNU Parallel 吗? parallel -k echo {#} {1} {2} {3} ::: A B C ::: A B C ::: A B C
  • 这确实简化了代码array=(A B C D E) && parallel -k echo {#} {1}word1{2}word2{3}word3 ::: ${array[*]} ::: ${array[*]} ::: ${array[*]}

标签: arrays bash for-loop


【解决方案1】:

使用递归。

#! /bin/bash
array=(A B C)
words=(word1 word2)

combine () {
    local depth=$1
    local prefix=${2# }
    shift 2
    if ((depth == ${#array[@]})) ; then
        echo "$prefix"
        return
    fi

    local i
    for (( i=1; i<=$#; ++i )) ; do
        combine $((depth+1)) "$prefix${!i}${words[depth]}" "${array[@]}"
    done
}

combine 0 "" "${array[@]}"

【讨论】:

  • 如果我将数组从 (A B C) 更改为 (A B C D),它的工作方式与我给出的示例不同。
  • @YoloYolovich:您也需要将单词更改为 (words1 words2 words3)。
  • 可能有 5 个字母和 2 个单词,因此与字母数组相比,它并不总是 n-1。
  • 哦,你想把最终条件改成((depth == 1 + ${#words[@]}))吗?
【解决方案2】:

查看awk 解决方案,该解决方案使用递归函数来允许动态数量的for 循环。

但首先要对输入参数进行一些修改(以便更轻松地将信息传递到awk);我们将用简单的变量替换bash 级别数组(使用: 作为本练习的分隔符):

array_s="A:B:C:D"
words_s="${word1}:${word2}"

一个awk想法:

awk -v places="${places}" -v words_s="${words_s}" -v array_s="${array_s}" '

function print_place(place,outstring, j, sfx) {        # define but do not pass "j" and "sfx"; 
                                                       # this designates these as local variables

if ( place > places )                                  # if we haveve exceeded the number of places ...
   { i++                                               # increment our counter
     printf "%s\n", outstring                          # print our string to stdout
     return                                            # and exit this invocation of the function
   }
if ( i > total ) return                                # if we have exceeded total number of outputs
                                                       # then exit this invocation of the function

sfx=""                                                 # default suffix is "" unless we
if ( place < places ) sfx=words[place]                 # have not reached the max number of places

for ( j=1 ; j<=n ; j++ )                               # loop through arr[] entries
    print_place(place+1,outstring arr[j] sfx)          # recursive function call for place+1; also pass along 
                                                       # our growing string
}

BEGIN { n=split(array_s,arr,":")                       # parse "array_s" into awk array "arr[]"
        m=split(words_s,words,":")                     # parse "words_s" into awak array "words[]"
        total=n**places                                # calculate total number of strings to print

        i=0                                            # init counter
        print_place(1,"")                              # call function
}
'

一些示例运行:

places=3
array_s="A:B:C"
words_s="word1:word2"

awk ...

Aword1Aword2A
Aword1Aword2B
Aword1Aword2C
Aword1Bword2A
Aword1Bword2B
Aword1Bword2C
...snip...
Cword1Cword2A
Cword1Cword2B
Cword1Cword2C                        # 27 lines of output

##############

places=2
array_s="A:B:C:D"
words_s="word1:word2"

awk ...

Aword1A
Aword1B
Aword1C
Aword1D
Bword1A
Bword1B
Bword1C
Bword1D
Cword1A
Cword1B
Cword1C
Cword1D
Dword1A
Dword1B
Dword1C
Dword1D                        # 16 lines of output

##############

places=4
array_s="A:B:C:D"
words_s="word1:word2:word3"

awk ...

Aword1Aword2Aword3A
Aword1Aword2Aword3B
Aword1Aword2Aword3C
Aword1Aword2Aword3D
Aword1Aword2Bword3A
Aword1Aword2Bword3B
Aword1Aword2Bword3C
Aword1Aword2Bword3D
Aword1Aword2Cword3A
Aword1Aword2Cword3B
...snip...
Dword1Dword2Cword3D
Dword1Dword2Dword3A
Dword1Dword2Dword3B
Dword1Dword2Dword3C
Dword1Dword2Dword3D                        # 256 lines of output

【讨论】:

    猜你喜欢
    • 2019-06-06
    • 2016-07-14
    • 2021-08-09
    • 2020-06-03
    • 2010-10-03
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多