linux – 如何使用大括号扩展变量

linux – 如何使用大括号扩展变量,第1张

概述参见英文答案 > Brace expansion with variable?                                     6个 我有四个文件: 1.txt 2.txt 3.txt 4.txt 在linux shell中,我可以使用: ls {1..4} .txt列出所有四个文件 但如果我设置两个变量:var1 = 1和var2 = 4,如何列出这四个文件? 那是 参见英文答案 > Brace expansion with variable?                                     6个
我有四个文件:

1.txt  2.txt  3.txt  4.txt

在linux shell中,我可以使用:
ls {1..4} .txt列出所有四个文件
但如果我设置两个变量:var1 = 1和var2 = 4,如何列出这四个文件?
那是:

var1=1var2=4ls {$var1..$var2}.txt  # error

什么是正确的代码?

解决方法 使用 brace expansion的序列表达形式({< numFrom> ..< numTo>})的变量仅适用于ksh和zsh,但遗憾的是,不在bash中(并且(大多数情况下)严格来说仅限POSIX特征的shell如破折号根本不支持撑杆扩张,因此应完全避免撑杆扩展/ bin / sh).

鉴于你的症状,我假设你正在使用bash,你只能在序列表达式中使用文字(例如{1..3});从manual(强调我的):

Brace expansion is performed before any other expansions,and any characters special to other expansions are preserved in the result.

换句话说:在评估大括号表达式时,尚未扩展(解析)变量引用;因此,将$var1和$var2等文字解释为序列表达式上下文中的数字会失败,因此大括号表达式被视为无效且未展开.
但请注意,变量引用是扩展的,即在整体扩展的后期阶段;在手边的情况下,字面结果是单个单词'{1..4}’ – 展开变量值的未展开大括号表达式.

虽然括号扩展的列表形式(例如,{foo,bar))以相同的方式扩展,但后来的变量扩展在那里不是问题,因为不需要预先解释列表元素;例如{$var1,$var2}正确导致2个单词1和4.
至于为什么变量不能用于序列表达式:历史上,括号扩展的列表形式首先出现,当后来引入序列表达形式时,扩展的顺序已经固定.
有关支架扩展的一般概述,请参阅this answer.

解决方法

注意:变通方法的重点是数字序列表达式,如问题所示;基于eval的变通方法还演示了如何使用不太常见的字符序列表达式的变量,这些表达式产生英文字母范围(例如,{a..c}以产生b c).

可以使用基于seq的解决方法,as demonstrated in Jameson’s answer.

一个小小的警告是seq不是POSIX实用程序,但大多数现代的类Unix平台都有它.

要稍微改进一下,使用seq的-f选项提供printf样式的格式字符串,并演示两位数的零填充:

seq -f '%02.f.txt' $var1 $var2 | xargs ls # '%02.f'==zero-pad to 2 digits,no decimal places

请注意,要使其完全健壮 – 如果生成的单词包含空格或制表符 – 您需要使用嵌入式引用:

seq -f '"%02.f a.txt"' $var1 $var2 | xargs ls

然后看到01 a.txt,02 a.txt,…正确保留了参数边界.

如果你想首先在Bash数组中稳健地收集结果单词,例如${words [@]}:

IFS=$'\n' read -d '' -ra words < <(seq -f '%02.f.txt' $var1 $var2)ls "${words[@]}"

以下是纯Bash解决方法:

使用Bash功能的有限解决方法是使用eval:

var1=1 var2=4# Safety check(( 10#$var1 + 10#$var2 || 1 )) 2>/dev/null || { echo "Need decimal integers." >&2; exit 1; }ls $(eval printf '%s\ ' "{$var1..$var2}.txt") # -> ls 1.txt 2.txt 3.txt 4.txt

您可以将类似的技术应用于字符序列表达式;

var1=a var2=c# Safety check[[ $var1 == [a-zA-Z] && $var2 == [a-zA-Z] ]] || { echo "Need single letters."; exit 1; }ls $(eval printf '%s\ ' "{$var1..$var2}.txt") # -> ls a.txt b.txt c.txt

注意:

>预先执行检查以确保$var1和$var2包含十进制整数或单个英文字母,这样可以安全地使用eval.通常,使用带有未经检查的输入的eval是一种安全风险,因此最好避免使用eval.
>鉴于eval的输出必须在此处不加引号传递给ls,以便shell通过单词拆分将输出拆分为单个参数,这仅在生成的文件名不包含嵌入空格或其他shell元字符时才有效.

一个更强大但更麻烦的纯Bash解决方法,使用数组创建等效的单词:

var1=1 var2=4# Emulate brace sequence Expression using an array.args=()for (( i = var1; i <= var2; i++ )); do  args+=( "$i.txt" )donels "${args[@]}"

>此方法不存在安全风险,也适用于带有嵌入式shell元字符(如空格)的结果文件名.>可以通过将i替换为例如i = 2来以2为增量步长来实现自定义增量.>实现零填充需要使用printf;例如,如下:args =(“$(printf’?d.txt’”$i“)”)# – > ’01 .txt’,’02 .txt’,…

总结

以上是内存溢出为你收集整理的linux – 如何使用大括号扩展变量全部内容,希望文章能够帮你解决linux – 如何使用大括号扩展变量所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/yw/1023600.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存