String 防止在';对于循环';

String 防止在';对于循环';,string,bash,for-loop,variables,String,Bash,For Loop,Variables,我必须编写一个bash脚本来忽略变量中的特定字符串,以防止文件混淆。我对bash非常陌生,不知道如何编写一行代码来检查非法的变量/字符串组合 例如,字符串大理石和火成岩不应在For循环中一起使用。这是需要更改的代码: #!/bin/bash IGNEOUS_BLOCK=(aa adakite pahoehoe) METAMORPHIC_BLOCK=(eclogite marble) SEDIMENTARY_BLOCK=(argillite chalk jaspillite) ROCK_

我必须编写一个bash脚本来忽略变量中的特定字符串,以防止文件混淆。我对bash非常陌生,不知道如何编写一行代码来检查非法的变量/字符串组合

例如,字符串
大理石
火成岩
不应在For循环中一起使用。这是需要更改的代码:

    #!/bin/bash

IGNEOUS_BLOCK=(aa adakite pahoehoe)
METAMORPHIC_BLOCK=(eclogite marble)
SEDIMENTARY_BLOCK=(argillite chalk jaspillite)
ROCK_TYPE=(igneous_rocks metamorphic_rocks sedimentary_rocks)

#Buttons
  for igneous_block in "${IGNEOUS_BLOCK[@]}" ; do
  for rock_type in "${ROCK_TYPE[@]}" ; do
      printf "{
    \"parent\": \"block/button\",
    \"textures\": {
        \"texture\": \"strata:blocks/"$rock_type"/"$igneous_block"\"
    }
}"> "${igneous_block}_button.json"
  done;
  done;
这就是它应该做的:

如果变量
岩石类型
使用字符串
火成岩
则应仅拾取
火成岩块
内部的字符串,而不是从
变质岩块
沉积岩块

这就是我希望所有变量都起作用的原因:

ROCK_TYPE
循环使用可用的字符串

ROCK_TYPE=(igneous_rocks metamorphic_rocks sedimentary_rocks)
火成岩块
只能使用字符串
火成岩

IGNEOUS_BLOCK=(aa adakite pahoehoe)
METAMORPHIC_BLOCK=(aa adakite pahoehoe)
SEDIMENTARY_BLOCK=(aa adakite pahoehoe)
变质岩块
仅允许使用管柱
变质岩

IGNEOUS_BLOCK=(aa adakite pahoehoe)
METAMORPHIC_BLOCK=(aa adakite pahoehoe)
SEDIMENTARY_BLOCK=(aa adakite pahoehoe)
沉积岩块
只能使用管柱
沉积岩

IGNEOUS_BLOCK=(aa adakite pahoehoe)
METAMORPHIC_BLOCK=(aa adakite pahoehoe)
SEDIMENTARY_BLOCK=(aa adakite pahoehoe)

我的代码需要做哪些更改才能像我希望的那样工作?

您似乎想要嵌套数据,其中
ROCK\u TYPE
是一个类型数组,每个类型都有一个子类型数组

在真正的编程语言中,可以使用嵌套的数据结构,这将使这变得非常容易,但不幸的是,Bash只有一个真正用于模拟嵌套数据的结构

相反,您可以使用语句定义要迭代的块数组:

#!/bin/bash

rock_types=(igneous_rocks metamorphic_rocks sedimentary_rocks)

for rock_type in "${rock_types[@]}"; do
    case $rock_type in
    igneous_rocks)
        blocks=(aa adakite pahoehoe)
        ;;
    metamorphic_rocks)
        blocks=(eclogite marble)
        ;;
    sedimentary_rocks)
        blocks=(argillite chalk jaspillite)
        ;;
    esac
    for block in "${blocks[@]}"; do
        echo "$rock_type/$block"
    done
done
输出:

火成岩/aa
火成岩/埃达克岩
火成岩/火成岩
变质岩/榴辉岩
变质岩/大理岩
沉积岩/泥板岩
沉积岩/白垩
沉积岩/碧玉岩
顺便说一句,所有caps变量名称都应该为环境变量(如
PATH
)和其他特殊变量(如
RANDOM
)保留

  • OP希望在岩石类型数组中列出的所有岩石类型中循环
  • 每个岩石类型和匹配的*\u块数组都有匹配的名称,a)数组名称都是大写的,b)字符串
    岩石
    替换为

一种相对简单的方法是使用
case
语句根据当前岩石类型确定要引用哪个**\u块体数组

验证想法的第一步:

for rtype in "${ROCK_TYPE[@]}"
do
    echo "+++++ rock type = ${rtype}"

    case "${rtype}" in
        igneous_rocks)          printf "%s\n" "${IGNEOUS_BLOCK[@]}"     ;;
        metamorphic_rocks)      printf "%s\n" "${METAMORPHIC_BLOCK[@]}" ;;
        sedimentary_rocks)      printf "%s\n" "${SEDIMENTARY_BLOCK[@]}" ;;
    esac
done
由此产生:

+++++ rock type = igneous_rocks
aa
adakite
pahoehoe
+++++ rock type = metamorphic_rocks
eclogite
marble
+++++ rock type = sedimentary_rocks
argillite
chalk
jaspillite
.igneous_rocks.igneous_block.aa.
.igneous_rocks.igneous_block.adakite.
.igneous_rocks.igneous_block.pahoehoe.
.metamorphic_rocks.metamorphic_block.eclogite.
.metamorphic_rocks.metamorphic_block.marble.
.sedimentary_rocks.sedimentary_block.argillite.
.sedimentary_rocks.sedimentary_block.chalk.
.sedimentary_rocks.sedimentary_block.jaspillite.
有几种方法可以修改它,以允许在关联的*\u块数组中循环各个值,例如:

for rtype in "${ROCK_TYPE[@]}"
do
        bname=${rtype//rocks/block}        # OPs example could use this for the 'texture' field and json file name

        for btype in $(case "${rtype}" in
                        igneous_rocks)          echo "${IGNEOUS_BLOCK[@]}"     ;;
                        metamorphic_rocks)      echo "${METAMORPHIC_BLOCK[@]}" ;;
                        sedimentary_rocks)      echo "${SEDIMENTARY_BLOCK[@]}" ;;
                       esac)
        do
                echo ".${rtype}.${bname}.${btype}."
        done
done
由此产生:

+++++ rock type = igneous_rocks
aa
adakite
pahoehoe
+++++ rock type = metamorphic_rocks
eclogite
marble
+++++ rock type = sedimentary_rocks
argillite
chalk
jaspillite
.igneous_rocks.igneous_block.aa.
.igneous_rocks.igneous_block.adakite.
.igneous_rocks.igneous_block.pahoehoe.
.metamorphic_rocks.metamorphic_block.eclogite.
.metamorphic_rocks.metamorphic_block.marble.
.sedimentary_rocks.sedimentary_block.argillite.
.sedimentary_rocks.sedimentary_block.chalk.
.sedimentary_rocks.sedimentary_block.jaspillite.
注意:句点作为可视分隔符添加


另一个想法是使用
nameref
(即,一个变量的值用作另一个变量的名称)

注意:我包括了这个选项,因为示例显示了类似命名的岩石类型和块体名称,这反过来使得
nameref
解决方案相对容易实现

考虑以下(简单)示例:

或者:

$ unset x h
$ x=5
$ typeset -n h=x     # define nameref
$ echo $x
5
$ echo $h
5
$ x=10
$ echo $h
10
使用
nameref
s解决岩石/块体问题的一个想法:

for rtype in "${ROCK_TYPE[@]}"
do
        bname=${rtype//rocks/block}                     # again, use this for the 'texture' field and json file name

        typeset -u -n currblock=${rtype//rocks/BLOCK}   # define nameref, convert to all uppercase and replace 'rocks' with 'BLOCK'

        for btype in "${currblock[@]}"                  # loop through nameref'd values
        do
                echo ".${rtype}.${bname}.${btype}."
        done
done
它生成与
案例
解决方案相同的输出集:

.igneous_rocks.igneous_block.aa.
.igneous_rocks.igneous_block.adakite.
.igneous_rocks.igneous_block.pahoehoe.
.metamorphic_rocks.metamorphic_block.eclogite.
.metamorphic_rocks.metamorphic_block.marble.
.sedimentary_rocks.sedimentary_block.argillite.
.sedimentary_rocks.sedimentary_block.chalk.
.sedimentary_rocks.sedimentary_block.jaspillite.
注意:同样,作为可视分隔符添加的句点包含以下代码:

IGNEOUS_BLOCK=(aa adakite pahoehoe)
METAMORPHIC_BLOCK=(eclogite marble)
SEDIMENTARY_BLOCK=(argillite chalk jaspillite)
ROCK_TYPE=(igneous_rocks metamorphic_rocks sedimentary_rocks)
for i in "${ROCK_TYPE[@]}"; do
    # convert to upercase, replace rocks
    n="${i//_rocks/_BLOCK}"
    n="${n^^}[@]"
    # Using indirect expansion
    for j in "${!n}"; do
       echo "$i/$j"
    done
done
将输出:

igneous_rocks/aa
igneous_rocks/adakite
igneous_rocks/pahoehoe
metamorphic_rocks/eclogite
metamorphic_rocks/marble
sedimentary_rocks/argillite
sedimentary_rocks/chalk
sedimentary_rocks/jaspillite
注意:按照惯例,大写变量用于导出变量,如PWD行列UID EID TERM LC_ALL COUNTRY HISTSIZE等。希望在脚本中使用小写变量

您可以使用与数组元素相同的方式命名变量,从而避免使用某些代码:

igneous_rocks=(aa adakite pahoehoe)
metamorphic_rocks=(eclogite marble)
sedimentary_rocks=(argillite chalk jaspillite)
rock_types=(igneous_rocks metamorphic_rocks sedimentary_rocks)
for i in "${rock_types[@]}"; do
    n="${i}[@]"
    for j in "${!n}"; do
       echo "$i/$j"
    done
done
作为间接扩展的替代方案,还有一个namereference


而不是使用bash/shell生成客户机数据文件,因为它不是非常可移植且难以维护,这迟早会让您感到不快,因为它是另一个要添加到构建环境中的框架和工具集

您最好使用Minecraft Forge项目记录的专用Gradle任务实现数据生成器:

如果你还真的想用bash做这件事。如果使用nameref变量动态引用相应的岩石类型数组,则代码可以工作:

#/usr/bin/env bash
#shellcheck disable=SC2034#已使用nameref
火成岩=('aa''埃达克岩''pahoehoe')
#shellcheck disable=SC2034#已使用nameref
变质岩=(‘榴辉岩’‘大理石’)
#shellcheck disable=SC2034#已使用nameref
沉积岩=(‘泥板岩’‘白垩岩’‘碧玉岩’)
岩石类型=(‘火成岩’‘变质岩’‘沉积岩’)
#钮扣
声明-n岩石类型
对于“${rock_types[@]}”中的rock_type;做
对于“${rock_type[@]}”中的rock_名称;做
cat“${rock\u name}\u button.json”
完成
完成

两个
用于
执行
,但只有一个
完成
?添加一个shebang,然后将您的脚本粘贴到那里:我将代码更改为完成两个
而不是一个
,并在顶部添加了一个shebang,但我仍然在“aa”边使用了“沉积岩”。我该怎么解决?继续检查。shebang不应该缩进,双引号是错误的。但这似乎不是问题所在,在bash中执行代码似乎完全没问题。ShellCheck只推荐编写代码的替代方案。这些文件确实会像应该的那样生成,但代码中使用的字符串顺序是错误的。此外,双引号可以以多种方式使用。我还发现,大部分代码都可以用双引号或单引号括起来。是的,我问,为什么变量不命名为
火成岩=(aa adakite pahoehoe)
,而是一些随机的
火成岩块
?您为什么要将
火成岩
转换为
火成岩块
?为什么不在f中命名变量
火成岩