Brace Expansion

Brace 확장은 여러 확장과 치환 중에서 제일 먼저 일어나는 작업입니다. 그러므로 brace 확장에 사용되는 start, end range 값으로 변수를 사용할 수 없습니다 (변수확장이 뒤에 일어나므로). quote 을 하면 brace 확장이 일어나지 않습니다.

Brace 확장은 readline 라이브러리 에서 제공되는 기능으로 sh 에서는 사용할 수 없습니다.

String lists

{string1,string2,...,stringN}

, 가 사용되지 않은 단일 항목은 확장되지 않으며 , 전,후에 공백을 사용할 수 없습니다. string 내에 공백이 포함될 경우 quote 합니다.

# ',' 가 사용되지 않은 단일 항목은 확장되지 않는다.
$ echo {hello}
{hello}

# ',' 전,후에 공백이 사용되면 확장이 되지 않는다.
$ echo X{apple, banana, orange, melon}Y
X{apple, banana, orange, melon}Y

# string 내에 공백이 포함될 경우 quote 한다.
$ echo X{apple,"ban ana",orange,melon}Y
XappleY Xban anaY XorangeY XmelonY

prefix 과 suffix 의 사용.

$ echo X{apple,banana,orange,melon}         # 여기서 X 는 prefix
Xapple Xbanana Xorange Xmelon

$ echo {apple,banana,orange,melon}Y         # Y 는 suffix
appleY bananaY orangeY melonY

# prefix, suffix 가 없을 경우 단지 space 로 분리되어 표시됩니다.
$ echo {apple,banana,orange,melon}         
apple banana orange melon    

$ echo X{apple,banana,orange,melon}Y
XappleY XbananaY XorangeY XmelonY

# '/home/bash/test/' 가 prefix 에 해당
$ mkdir /home/bash/test/{foo,bar,zoo}

$ ls /home/bash/test/
bar/  foo/  zoo/
--------------------------------------

$ echo --exclude={./public_html/cache,./public_html/images}
--exclude=./public_html/cache --exclude=./public_html/images

$ tar -czvf backup-`date +%m-%d-%Y-%H%M`.tar.gz \
     --exclude={./public_html/cache,./public_html/images} \
     ./public_html
-----------------------------------------------------------

# 'http://docs.example.com/slides_part' 는 prefix '.html' 는 suffix 에 해당
$ curl --remote-name-all http://docs.example.com/slides_part{1,2,3,4}.html

$ ls
slides_part1.html slides_part2.html slides_part3.html slides_part4.html
--------------------------------------------------------------------------

$ echo perl -V:{short,int,long{,long}}size
perl -V:shortsize -V:intsize -V:longsize -V:longlongsize

$ perl -V:{short,int,long{,long}}size
shortsize='2';
intsize='4';
longsize='8';
longlongsize='8';

globbing 과 함께 사용

$ mv *.{png,gif,jpg} ~/Pictures/
$ mv *.{avi,mp4,mkv} ~/Videos/

null 값의 활용

$ echo foo{,}1
foo1 foo1

$ echo foo{,,}2
foo2 foo2 foo2

$ cp test.sh{,.bak}
$ ls
test.sh test.sh.bak

$ ls /usr/local/{,foo/}bar
/usr/local/bar 
. . .
/usr/local/foo/bar
. . .

$ echo <( echo x ){,,}
/dev/fd/63 /dev/fd/62 /dev/fd/61
$ cat <( shuf -n5 -i 1-99 )
91
52
15
73
64
$ paste <( shuf -n5 -i 1-99 ){,,} 
48      18      91
58      24      95
91      54      66
31      14      10
44      8       55

변수와 같이 사용한 예

$ AA=foo

$ echo {a,b}$AA            # a$AA b$AA 가 된다.
afoo bfoo

$ AA1=aa AA2=bb AA3=cc
# 변수확장 보다 brace 확장이 먼저 일어나므로 $AA1 $AA2 $AA3 가 된다
$ echo $AA{1..3}
aa bb cc

# 그냥 $AA 로 사용하면 X$AAY 와 같아지므로 ${AA} 나 "$AA" 를 사용해야 합니다.
$ echo X{apple,${AA},orange,melon}Y
XappleY XhelloY XorangeY XmelonY

Ranges

{< START >...< END > }
{< START >...< END >...< INCR >}

Brace 확장은 변수확장 보다 먼저 일어납니다. 그러므로 start, end 값을 변수로 사용할 수 없습니다.

$ a=1 b=10

$ echo {$a..$b}         # brace 확장이 되지 않는다.      
{1..10}

start, end 값으로 숫자와 알파벳을 사용할수 있습니다.

$ echo {5..12}
5 6 7 8 9 10 11 12

$ echo {c..k}
c d e f g h i j k

$ echo {5..k}          # 숫자와 알파벳을 섞어서 사용할수는 없습니다.
{5..k}

$ echo {1..5}{0,5}%
10% 15% 20% 25% 30% 35% 40% 45% 50% 55%

######## Increment ########

$ echo {1..10..2}
1 3 5 7 9
$ echo {10..1..2}
10 8 6 4 2

$ echo {10..50..5}%
10% 15% 20% 25% 30% 35% 40% 45% 50%

$ echo {a..z..3}
a d g j m p s v y

zero 패딩

$ echo {01..100}
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 
021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 
041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 
061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 
081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 100

# img001.png ~ img999.png 까지 생성
printf "%s\n" img{00{1..9},0{10..99},{100..999}}.png

prefix 또는 suffix 의 사용.

$ echo 1.{0..9}
1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9

$ echo __{A..E}__
__A__ __B__ __C__ __D__ __E__

$ echo {A..D}___{1..3}
A___1 A___2 A___3 B___1 B___2 B___3 C___1 C___2 C___3 D___1 D___2 D___3

# 'http://docs.example.com/slides_part' 는 prefix '.html' 는 suffix 에 해당
$ curl --remote-name-all http://docs.example.com/slides_part{1..4}.html
$ ls
slides_part1.html slides_part2.html slides_part3.html slides_part4.html

Combining and nesting

임의의 스트링은 Union (Alternation) , Concatenation , Kleene Closure , Positive Closure 4 가지 방법을 이용해 만들수가 있는데요 ( 참조 ). 이중에서 Concatenation 에 해당합니다.

{ } 에서 .. range 를 사용하여 서로 붙이면 combining 이 일어납니다.

$ echo {AD}{03}
{AD}{03}

$ echo {A..D}{03}
A{03} B{03} C{03} D{03}

$ echo {A..D}{0..3}
A0 A1 A2 A3 B0 B1 B2 B3 C0 C1 C2 C3 D0 D1 D2 D3

$ echo {A..Z}{0..9}
A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 C0 C1 C2 C3 C4 C5 C6
C7 C8 C9 D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 F0 F1 F2 F3
F4 F5 F6 F7 F8 F9 G0 G1 G2 G3 G4 G5 G6 G7 G8 G9 H0 H1 H2 H3 H4 H5 H6 H7 H8 H9 I0
I1 I2 I3 I4 I5 I6 I7 I8 I9 J0 J1 J2 J3 J4 J5 J6 J7 J8 J9 K0 K1 K2 K3 K4 K5 K6 K7
K8 K9 L0 L1 L2 L3 L4 L5 L6 L7 L8 L9 M0 M1 M2 M3 M4 M5 M6 M7 M8 M9 N0 N1 N2 N3 N4
N5 N6 N7 N8 N9 O0 O1 O2 O3 O4 O5 O6 O7 O8 O9 P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 Q0 Q1
Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 S0 S1 S2 S3 S4 S5 S6 S7 S8
S9 T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 U0 U1 U2 U3 U4 U5 U6 U7 U8 U9 V0 V1 V2 V3 V4 V5
V6 V7 V8 V9 W0 W1 W2 W3 W4 W5 W6 W7 W8 W9 X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 Y0 Y1 Y2
Y3 Y4 Y5 Y6 Y7 Y8 Y9 Z0 Z1 Z2 Z3 Z4 Z5 Z6 Z7 Z8 Z9

$ echo {0..2}.{0..9}{0..9..5} 3.00
0.00 0.05 0.10 0.15 0.20 0.25 0.30 0.35 0.40 0.45 0.50 0.55 0.60 0.65 0.70 0.75 0.80
0.85 0.90 0.95 1.00 1.05 1.10 1.15 1.20 1.25 1.30 1.35 1.40 1.45 1.50 1.55 1.60 1.65
1.70 1.75 1.80 1.85 1.90 1.95 2.00 2.05 2.10 2.15 2.20 2.25 2.30 2.35 2.40 2.45 2.50
2.55 2.60 2.65 2.70 2.75 2.80 2.85 2.90 2.95 3.00

$ seq -s, 0 0.05 3.0
0.00,0.05,0.10,0.15,0.20,0.25,0.30,0.35,0.40,0.45,0.50,0.55,0.60,0.65,0.70,0.75,0.80,
0.85,0.90,0.95,1.00,1.05,1.10,1.15,1.20,1.25,1.30,1.35,1.40,1.45,1.50,1.55,1.60,1.65,
1.70,1.75,1.80,1.85,1.90,1.95,2.00,2.05,2.10,2.15,2.20,2.25,2.30,2.35,2.40,2.45,2.50,
2.55,2.60,2.65,2.70,2.75,2.80,2.85,2.90,2.95,3.00

$ echo \({A..C},{1..3}\)
(A,1) (A,2) (A,3) (B,1) (B,2) (B,3) (C,1) (C,2) (C,3)

{ } 안에서 식을 작성하면 , 는 값을 분리하는 역할을 합니다.

$ echo {A..D},{1..4}
A,1 A,2 A,3 A,4 B,1 B,2 B,3 B,4 C,1 C,2 C,3 C,4 D,1 D,2 D,3 D,4

$ echo {{A..D},{1..4}}     # { } 안에서 식을 작성하여 값이 분리된다.
A B C D 1 2 3 4

$ echo {{A..D}{1..4}}
{A1} {A2} {A3} {A4} {B1} {B2} {B3} {B4} {C1} {C2} {C3} {C4} {D1} {D2} {D3} {D4}

$ echo {{0..5},{0..5}{0..5..5},{6..10}}
0 1 2 3 4 5 00 05 10 15 20 25 30 35 40 45 50 55 6 7 8 9 10

$ echo 0.{00{0..9},0{10..99},100}
0.000 0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009 0.010 0.011 0.012 0.013
0.014 0.015 0.016 0.017 0.018 0.019 0.020 0.021 0.022 0.023 0.024 0.025 0.026 0.027
0.028 0.029 0.030 0.031 0.032 0.033 0.034 0.035 0.036 0.037 0.038 0.039 0.040 0.041
0.042 0.043 0.044 0.045 0.046 0.047 0.048 0.049 0.050 0.051 0.052 0.053 0.054 0.055
0.056 0.057 0.058 0.059 0.060 0.061 0.062 0.063 0.064 0.065 0.066 0.067 0.068 0.069
0.070 0.071 0.072 0.073 0.074 0.075 0.076 0.077 0.078 0.079 0.080 0.081 0.082 0.083
0.084 0.085 0.086 0.087 0.088 0.089 0.090 0.091 0.092 0.093 0.094 0.095 0.096 0.097
0.098 0.099 0.100

for 문에서 사용 가능

Brace 확장은 for 문에서 사용이 가능합니다. seq 외부 명령 사용과 비교했을 때 불필요한 프로세스 생성을 줄일 수 있어 효율적입니다.

$ for i in {1..5}; do echo $i; done         $ for i in $(seq 5); do echo $i; done
1                                           1
2                                           2
3                                           3
4                                           4
5                                           5

Range 값으로 변수를 사용하려면?

eval 명령을 사용하면 range 값으로 변수를 사용할 수 있습니다.

$ a=1 b=5
$ eval echo {$a..$b}    # eval 명령을 이용하면 원하는 결과를 얻을수 있습니다.
1 2 3 4 5

$ eval echo img{$a..$b}.png
img1.png img2.png img3.png img4.png img5.png

Brace 확장을 피하려면?

{ or } 를 escape 하거나 quote 해주면 됩니다.

$ echo \{a..c}
{a..c}

$ echo {a..c\}
{a..c}

Quiz

Brace 확장을 활용하면 동일한 명령을 인수를 바꿔가며 여러번 실행시키는 것을 간단히 할 수 있습니다.

$ echo 'grep -c '{foo,bar,zoo}' '{data1,data2,data3}';'
grep -c foo data1; grep -c foo data2; grep -c foo data3; 
grep -c bar data1; grep -c bar data2; grep -c bar data3; 
grep -c zoo data1; grep -c zoo data2; grep -c zoo data3;

$ eval 'grep -H -c '{foo,bar,zoo}' '{data1,data2,data3}';'
data1:12    # foo
data2:3
data3:15
data1:0     # bar
data2:5
data3:9
data1:7     # zoo
data2:19
data3:2

2 .

다음 명령 실행 결과는 어떻게 될까요?

$ echo bash{,e{d,s},ful{,ly,ness},ing}

bash bashed bashes bashful bashfully bashfulness bashing

https://youtu.be/uqHjc7hlqd0?t=2148

다음은 complete-into-braces 라는 기능인데 파일이름 자동완성을 brace 확장으로 만들어 줍니다.

$ cd /bin

# z + ESC + { 입력
$ echo z{c{at,mp},d{iff,ump},e{grep,nity},f{grep,orce},grep,ip{,cloak,details,grep,info,note,split},jsdecode,less,more,new,run,s{h{,5},td{,cat,grep,less,mt}}} 

zcat zcmp zdiff zdump zegrep zenity zfgrep zforce zgrep zip zipcloak zipdetails zipgrep zipinfo zipnote zipsplit zjsdecode zless zmore znew zrun zsh zsh5 zstd zstdcat zstdgrep zstdless zstdmt

------------------------------------

$ bind -p | grep '{'
"\e{": complete-into-braces

$ LESS='+/complete-into-braces' man  bash
   complete-into-braces (M-{)
          Perform filename completion and insert the list of possible com‐
          pletions  enclosed within braces so the list is available to the
          shell (see Brace Expansion above).