如何使用括号扩展变量 [英] how to use variables with brace expansion
问题描述
我有四个文件:
1.txt 2.txt 3.txt 4.txt
在Linux shell中,我可以使用: LS {} 1..4 .TXT
来列出所有的四个文件
但如果我设置了两个变量:VAR1 = 1和var2 = 4,如何列出的四个文件?
那就是:
in linux shell, I could use :
ls {1..4}.txt
to list all the four files
but if I set two variables : var1=1 and var2=4, how to list the four files?
that is:
var1=1
var2=4
ls {$var1..$var2}.txt # error
什么是正确code?
what is the correct code?
推荐答案
使用的变量的用的序列-EX pression形式的( {< numFrom> ..< numTo>}
)的括号扩展 仅在 KSH
和的zsh
,但不幸的是,未在庆典
(和(主要是)严格POSIX的功能 - 只贝壳,如破折号
不支持括号扩展的所有的,所以括号扩展应该是避免 / bin / sh的
共有)。
Using variables with the sequence-expression form ({<numFrom>..<numTo>}
) of brace expansion only works in ksh
and zsh
, but, unfortunately, not in bash
(and (mostly) strictly POSIX-features-only shells such as dash
do not support brace expansion at all, so brace expansion should be avoided with /bin/sh
altogether).
由于你的症状,我假设你正在使用庆典
,在这里你可以只使用的文本的顺序前pressions (例如, {1..3}
);从手动(重点煤矿)
Given your symptoms, I assume you're using bash
, where you can only use literals in sequence expressions (e.g., {1..3}
); from the manual (emphasis mine):
支撑扩张的之前的任何其他扩展的,任何特殊的字符与其他扩展都在结果preserved执行。
Brace expansion is performed before any other expansions, and any characters special to other expansions are preserved in the result.
在换句话说:是在一个括号前pression进行评估的时候,变量引用没有被扩大(解决),但;除preting的文本的如 $ VAR1
和 $ VAR2
如数字因此序列的前pression的情况下出现故障,所以的括号前pression被视为无效,不扩大的。结果
但是请注意,该变量的引用是的扩大,即在整体扩张的稍后阶段;在本案字面结果就是一个字'{1..4}
- 未展开前撑pression具有扩展的变量值
In other words: at the time a brace expression is evaluated, variable references have not been expanded (resolved) yet; interpreting literals such as $var1
and $var2
as numbers in the context of a sequence expression therefore fails, so the brace expression is considered invalid and as not expanded.
Note, however, that the variable references are expanded, namely at a later stage of overall expansion; in the case at hand the literal result is the single word '{1..4}'
- an unexpanded brace expression with variable values expanded.
虽然列表的括号扩展(例如, {富,吧)
)展开同样的方式,后来变的形式扩张是不是一个问题出现,因为需要在前面的列表中的元素没有跨pretation;例如 {$ VAR1,$ VAR2}
正确导致2字 1
和 4
。结果
至于的为什么的变量不能按顺序前pressions使用:从历史上看,列表的括号扩展的形式首先出现,而当序列前pression后来形式引入,扩展的顺序已经固定。结果
对于括号扩展的概述,请参见这个答案。
While the list form of brace expansion (e.g., {foo,bar)
) is expanded the same way, later variable expansion is not an issue there, because no interpretation of the list elements is needed up front; e.g. {$var1,$var2}
correctly results in the 2 words 1
and 4
.
As for why variables cannot be used in sequence expressions: historically, the list form of brace expansion came first, and when the sequence-expression form was later introduced, the order of expansions was already fixed.
For a general overview of brace expansion, see this answer.
注:解决方法注重的数值的序列前pressions,如问题;在评估
基于解决办法也表明与不常见的字符的序列前pressions,而产生的英语范围的使用变量信的(例如, {a..c}
制作 ABC
)。
Note: The workarounds focus on numerical sequence expressions, as in the question; the eval
-based workaround also demonstrates use of variables with the less common character sequence expressions, which produce ranges of English letters (e.g., {a..c}
to produce a b c
).
A SEQ
基于解决方法是可能的,的在詹姆逊的答案证明。
A seq
-based workaround is possible, as demonstrated in Jameson's answer.
小需要注意的是 SEQ
不是POSIX工具,但大多数现代类Unix平台有它。
A small caveat is that seq
is not a POSIX utility, but most modern Unix-like platforms have it.
要完善它一点点,使用的序列
-f
选项提供一个的printf
风格的格式字符串,并展示两位数零填充:
To refine it a little, using seq
's -f
option to supply a printf
-style format string, and demonstrating two-digit zero-padding:
seq -f '%02.f.txt' $var1 $var2 | xargs ls # '%02.f'==zero-pad to 2 digits, no decimal places
请注意,要使其充分强劲 - 的情况下,所产生的字包含空格或制表符 - 你需要聘请的嵌入式报价的:
Note that to make it fully robust - in case the resulting words contain spaces or tabs - you'd need to employ embedded quoting:
seq -f '"%02.f a.txt"' $var1 $var2 | xargs ls
LS
然后看见 01 A.TXT
, 02 A.TXT
,...带参数的边界正确preserved。
ls
then sees 01 a.txt
, 02 a.txt
, ... with the argument boundaries correctly preserved.
如果您要有力收集产生的词语的一个猛砸的阵列的第一,如 $ {字[@]}
:
If you want to robustly collect the resulting words in a Bash array first, e.g., ${words[@]}
:
IFS=$'\n' read -d '' -ra words < <(seq -f '%02.f.txt' $var1 $var2)
ls "${words[@]}"
以下是的纯巴什解决方法:
A 限制的变通办法使用bash特性仅是为使用评估
:
A limited workaround using Bash features only is to use 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
您可以使用类似的技术,以一个 字符的序列前pression ;
You can apply a similar technique to a character sequence expression;
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
包含十进制整数或单英文字母,然后使其能够安全使用评估
。 一般情况下,使用评估
与选中的输入是一个安全隐患,并使用评估
的因此最好避免 - 鉴于从
评估
输出的必须的传递的不带引号到LS
在这里,让shell把通过文字分裂输出到各个参数,这仅在产生的文件名包含嵌入空格或其他shell元字符的工作。
- A check is performed up front to ensure that
$var1
and$var2
contain decimal integers or single English letters, which then makes it safe to useeval
. Generally, usingeval
with unchecked input is a security risk and use ofeval
is therefore best avoided. - Given that output from
eval
must be passed unquoted tols
here, so that the shell splits the output into individual arguments through words-splitting, this only works if the resulting filenames contain no embedded spaces or other shell metacharacters.
A 更健壮,更麻烦的纯巴什解决方法为使用数组以创建相同的单词:
A more robust, but more cumbersome pure Bash workaround to use an array to create the equivalent words:
var1=1 var2=4
# Emulate brace sequence expression using an array.
args=()
for (( i = var1; i <= var2; i++ )); do
args+=( "$i.txt" )
done
ls "${args[@]}"
- 这种做法不承担任何安全风险,也与嵌入式shell元字符,如空格产生的文件名的作品。
- 自定义的增量可以通过更换
实施我++
用,例如,I + = 2
来一步的增量为2 - 实施的零填充的需要使用
的printf的
;例如,如下所示:搜索ARGS + =($(printf的'%02d.txt'$ I))# - &GT; '01 .TXT','02 .TXT,...
- This approach bears no security risk and also works with resulting filenames with embedded shell metacharacters, such as spaces.
- Custom increments can be implemented by replacing
i++
with, e.g.,i+=2
to step in increments of 2. - Implementing zero-padding would require use of
printf
; e.g., as follows:
args+=( "$(printf '%02d.txt' "$i")" ) # -> '01.txt', '02.txt', ...
这篇关于如何使用括号扩展变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!