我将给出我所面临的问题的简短版本。我试图编写的实际应用程序有很多部分,因此我尝试用一个小示例来隔离我遇到的部分。我的情况涉及文件 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 循环内的任何内容,即在上面的示例中,我首先给出$line
as "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