【问题标题】:bash brace expansion based on variable content not working基于变量内容的bash大括号扩展不起作用
【发布时间】:2021-03-07 13:19:09
【问题描述】:

如何让 bash 扩展它在传递给 mkdir 的变量中找到的任何内容? 到目前为止,我已经尝试使用 evalbash -c,但似乎没有任何效果

LEVEL_1=1,2,3
LEVEL_2=a,b,c

DATA_L1="/tmp/{$LEVEL_1}"
DATA_L2="$DATA_L1/{$LEVEL_2}"

for LINE in $(cat file.txt) ; do
  #"cat" here returns values like 
  #$DATA_L2/yy/data

  mkdir -pv $LINE #it actually contains e.g. this $DATA_L2/yy/data
done

我希望这将扩展到

mkdir -p /tmp/1/a/yy/data
mkdir -p /tmp/2/a/yy/data
mkdir -p /tmp/3/a/yy/data
mkdir -p /tmp/1/b/yy/data
mkdir -p /tmp/2/b/yy/data
mkdir -p /tmp/3/b/yy/data
mkdir -p /tmp/1/c/yy/data
mkdir -p /tmp/2/c/yy/data
mkdir -p /tmp/3/c/yy/data

【问题讨论】:

  • 您没有在循环体中使用变量$LINE。您到底希望在这里发生什么?
  • 大括号扩展发生在参数扩展之前。另外,如果有的话,你是如何使用LINE 的?您是否正在编写 mkdir $LINE 并期待递归参数扩展?
  • 暂时忽略file.txt,你可以写for d in /tmp/{1,2,3}/{a,b,c}/yy/data; do mkdir -p "$d"; done
  • 简单的mkdir -p /tmp/{1,2,3}/{a,b,c}/yy/data 怎么样?
  • 您对 DATA_L1 的定义没有多大意义。这只会扩展为/tmp/{1,2,3},但应用逗号的时间早于参数扩展,这不会像您希望的那样扩展为/tmp/1 /tmp/2 /tmp/3。

标签: bash brace-expansion


【解决方案1】:

我怀疑这是XY problem,但一个选项可能是数组和for循环,类似于:

numbers=(1 2 3)
letters=(a b c)

dir="/tmp"

for letter in "${letters[@]}"; do
    for number in "${numbers[@]}"; do
        echo mkdir -pv "$dir/$number/$letter/yy/data"
    done
done

输出:

mkdir -pv /tmp/1/a/yy/data
mkdir -pv /tmp/2/a/yy/data
mkdir -pv /tmp/3/a/yy/data
mkdir -pv /tmp/1/b/yy/data
mkdir -pv /tmp/2/b/yy/data
mkdir -pv /tmp/3/b/yy/data
mkdir -pv /tmp/1/c/yy/data
mkdir -pv /tmp/2/c/yy/data
mkdir -pv /tmp/3/c/yy/data

【讨论】:

  • 我不认为这个问题是 xy 问题。实际需要的是在不进行任何循环的情况下创建这些目录,也就是使用大括号扩展。出于某种原因,我尝试过的每个组合(由于复杂的结构)都不起作用,并且由于工作的性质,我不想在这里发布完整的脚本(法律原因)。
  • @mispp 在这种情况下,创建一个minimal reproducible example 并明确给出你的约束。
  • 很公平。稍后我会对此进行研究,因为我必须继续处理其他问题。谢谢你们俩的解决方案。
  • @mispp,如果您有类似numbers_str="1,2,3" 的输入并希望得到此答案中给出的numbers=( 1 2 3 ),请考虑IFS=, read -r -a numbers <<<"$numbers_str"
【解决方案2】:

我怀疑您的问题是您有 层扩展,即使您没有在问题中表明这一点。也就是说,你显示:

mkdir -pv $DATA_L2/yy/data

如果您简单地向其添加 eval,这将起作用:

eval mkdir -pv $DATA_L2/yy/data

但是在你的循环中,你实际上并没有运行上面的命令。我认为您正在运行类似:

mkdir -pv $LINE

如果我们在mkdir 前面加上echo,我们可以看到:

echo mkdir -pv $LINE

结果:

mkdir -pv $DATA_L2/yy/data

还有:

eval echo mkdir -pv $LINE

结果:

mkdir -pv /tmp/{1,2,3}/{a,b,c}/yy/data

如果你 加倍 eval:

eval eval echo mkdir -pv $LINE

你得到你想要的:

mkdir -pv /tmp/1/a/yy/data /tmp/1/b/yy/data /tmp/1/c/yy/data /tmp/2/a/yy/data /tmp/2/b/yy/data /tmp/2/c/yy/data /tmp/3/a/yy/data /tmp/3/b/yy/data /tmp/3/c/yy/data

但是双重eval 是一个非常好的信号,需要重新考虑您解决问题的方法。

【讨论】:

  • 那里还有$LINE。我不小心把它漏掉了。将相应地更新问题。
  • 您的编辑符合我的假设,所以这个答案仍然适用。我怀疑@wjandrea 是在正确的轨道上 w/r/t 重新考虑你解决问题的方法。
  • 这实际上是我想要的。您使用斜体的这个“双重”评估解决了这个问题。即使它可能是 xy 问题,我不这么认为。我实际上想避免使用循环并用大括号扩展代替它。循环已经存在...
  • 您只需要一个双重评估,因为您在单一评估方法中没有正确引用。 eval "mkdir -pv $LINE" 带引号的行为正常。
猜你喜欢
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-09
  • 1970-01-01
相关资源
最近更新 更多