尝试使用 while read line 和 echo 进行 bash 大括号扩展(离散数字),但不会扩展

尝试使用 while read line 和 echo 进行 bash 大括号扩展(离散数字),但不会扩展

我将给出我所面临的问题的简短版本。我试图编写的实际应用程序有很多部分,因此我尝试用一​​个小示例来隔离我遇到的部分。我的情况涉及文件 ID 号,类似于从目录或其他内容解析的假设的学生 ID 号列表。


我从什么开始

为了尝试并利用bash 大括号扩展,类似学生目录的内容已被解析为以下内容:

$ cat student_id_potential_expansions
0000{11,24}
0001{32,38,81}
0002{02,80,81,89,97}

期望的行为

我想使用此输入来创建我自己的 (Bourne Again) shell 脚本,如下所示。

#!/bin/bash

get_transcripts_for_id.sh -id 000011
get_transcripts_for_id.sh -id 000024
get_transcripts_for_id.sh -id 000132
get_transcripts_for_id.sh -id 000133
get_transcripts_for_id.sh -id 000181
get_transcripts_for_id.sh -id 000202
...

等等

之前我不太担心这个命令;我想我只会用一个

awk '{print "get_transcripts_for_id.sh -id" $0}' student_id_list > my_shell_script.sh

或一个

sed 's/^\(.*\)$/get_transcripts_for_id.sh -id \1/' student_id_list > my_shell_script.sh

现在,我只是想student_id_list从潜在扩展列表中获取 id 号列表(上面的)。

我想我知道基本问题,只是不知道如何解决。我可以按如下方式获取我想要的列表的各个部分:

$ echo 0000{11,24} | tr ' ' '\n'
000011
000024

$ echo 0001{32,38,81} | tr ' ' '\n'
000132
000138
000181

$ echo 0002{02,80,81,89,97} | tr ' ' '\n'
000202
000280
000281
000289
000297

然而,我第一个想到的命令并没有扩展东西

# doesn't work, as you can see
$ while read -r line; do echo $line; done < student_id_potential_expansions
0000{11,24}
0001{32,38,81}
0002{02,80,81,89,97}

不要只想复制/粘贴每一行。我已经获得了数百到数千条可能可扩展的行 - 这些行是由其他人从不知道在哪里解析的,而且我无法访问从记录中进行原始解析的人。而且,我的每一行都更像

0000009{882,739,861,014,952,611,862,935,976,916,080,697,323,843,840,487,517,407,256,756,374,682,162,930,758,157,770,505,867,233,198,131,917,848,613,247,961,261,616,392,876,747,873,148,844,849,280,626,817,819,174,771,172,284,217,200,018,624,418,292,642,529,755,855,647,317,881,962,975,237,635,805,298,835,053}

我的理解

从 bash 手册中,第3.5.1节

大括号扩展是一种可以生成任意字符串的机制。
...
正确形成的大括号扩展必须包含未引用的左大括号和右大括号,以及至少一个未引用的逗号或有效的序列表达式。任何错误形成的大括号扩展都保持不变。

据我了解,当我阅读每一行时,我基本上给出了一个字符串,该字符串将被馈送到 while 循环内的任何内容,即在上面的示例中,我首先给出$lineas "0000{11,24}"(注意引号)。进一步进行下去,就好像我第一次循环会产生以下命令

echo "0000{11,24}"

再次注意引号,即使它们不在$line我的循环中while。为了看看这是否一致,我运行了以下命令并得到了以下结果:

$ echo "0000{11,24}"
0000{11,24}

$ echo "0001{32,38,81}"
0001{32,38,81}

$ echo "0002{02,80,81,89,97}"
0002{02,80,81,89,97}

因此,据我所知,所有的大括号 ({}) 和逗号都被引用 - bash 手册说这会导致无效的扩展语句。那么主要问题是,如何取消引用或取消字符串化$line我读入的每个内容?


我的尝试/研究

冒着这篇文章太长的风险,以下是我所做的一些尝试。

翻翻所以帖子,我很确定我的问题不是单词分离问题。

这个答案这条评论,特别是提到

在 中bash{}扩展发生在扩展之前,所以我认为除了使用或其他一些技巧来导致两次通过表达式$之外,没有其他方法可以做到这一点。eval

让我想到尝试

$ while read -r line; do eval "$line"; done < student_id_potential_expansions
bash: 000011: command not found
bash: 000132: command not found
bash: 000202: command not found

$ while read -r line; do echo $(eval "$line"); done < student_id_potential_expansions
bash: 000011: command not found

bash: 000132: command not found

bash: 000202: command not found

在 shell 尝试运行(评估)命令之前,似乎只执行了第一次扩展。

我还尝试了下面的命令,查看评论这里

$ while read -r line; do expansions=$line; echo $expansions; done < trying_inner_echo.txt
$(echo 0000{11,24})
$(echo 0001{32,38,81})
$(echo 0002{02,80,81,89,97})

$ while read -r line; do echo $line; done < trying_inner_echo.txt
$(echo 0000{11,24})
$(echo 0001{32,38,81})
$(echo 0002{02,80,81,89,97})

$ while read -r line; do threads=${line}; exec $threads; done < trying_inner_echo.efl
bash: exec: $(echo: not found
bash: exec: $(echo: not found
bash: exec: $(echo: not found

$ while read -r line; do threads=${line}; exec "${threads}"; done < trying_inner_echo.txt
bash: exec: $(echo 0000{11,24}): not found
bash: exec: $(echo 0001{32,38,81}): not found
bash: exec: $(echo 0002{02,80,81,89,97}): not found

其他一些尝试:

$ while read -r line; do echo "$line"; done < student_id_potential_expansions
$ while read -r line; do echo "$(echo $line)"; done < student_id_potential_expansions

系统信息

$ uname -a
CYGWIN_NT-10.0 C-D-ENG-E-INT3 2.11.2(0.329/5/3) 2018-11-08 14:34 x86_64 Cygwin

$ bash --version
GNU bash, version 4.4.12(3)-release (x86_64-unknown-cygwin)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

$ systeminfo | sed -n 's/^OS\ *//p'
Name:                   Microsoft Windows 10 Enterprise
Version:                10.0.17134 N/A Build 17134
Manufacturer:           Microsoft Corporation
Configuration:          Member Workstation
Build Type:             Multiprocessor Free

我用了什么(感谢@EchoMike444)

@EchoMike444 的答案绝对正确,让我到达了我需要去的地方,因此这是公认的答案。由于我使用的内容与答案中出现的内容略有不同,因此我将把它放在这里(而不是在答案的评论中)。来自评论:

谢谢你带我去那里。当我使用

while read -r line; do 
  eval "echo $line"  ## RIGHT!
done < student_id_potential_expansions | tr ' ' '\n' 

我得到了我正在寻找的输出。我需要帮助才能从 到达那里echo $(eval "$line") # wrong!

答案1

诀窍是使用eval

一个非常小的例子:

( echo '000{90,91}' ; echo '002{10,11}' ; echo '110{50,51}' ) | \
       while read L ; do eval "echo $L" | tr ' ' '\n'  ; done

相关内容