Creating script to cp directory multiple times

{2..5} is brace expansion. Brace expansion is not standardized by POSIX. Some, but not all, of the widely used Bourne-style shells support it.

The shell you interact with in a terminal on Ubuntu is bash, unless you're deliberately using a different one. bash supports brace expansion. But the shebang on your script is for sh, which on Ubuntu is a symlink to dash. dash does not support brace expansion.

So you can either:

  1. Make your script a bash script (or a script for some other shell that supports brace expansion, such as zsh or ksh).
  2. Replace brace expansion in your script with something that works in dash.

If you want to make your script a bash script, replace

#!/bin/sh

with:

#!/bin/bash

Then when run like ./scriptname it will be run in bash. If you're running your script by writing sh scriptname then you must use bash scriptname instead.


If you want to eliminate brace expansion, there are a few alternatives. I suggest seq with command substitution, which is probably the most common alternative to brace expansion, is easy to write, and is likely to be understood by other human readers.

In place of {2..5}, you can write $(seq 2 5). Since it is not quoted--that is, since it is $( ) and not "$( )"--field splitting (which in bash is called word splitting) is performed on the result. So long as you have not set the IFS shell variable, which controls field splitting, to a value that contains any digit or that does not contain a newline, this will do what you want.

(Globbing--also called filename expansion, also called pathname expansion--is also performed on the result of unquoted command substitution, but the output of seq will not contain the globbing characters ?, *, or [, so that has no effect in this case.)

Note that seq is not standardized by POSIX. This will work on just about any GNU/Linux system and some other Unix-like operating systems, but some Unix-like OSes don't have seq installed by default (they usually have jot instead) so it is not guaranteed to work on all Unix-like operating systems.


When you run the script in your terminal, the shell that you are using is most likely Bash. Bash supports brace expansion, so {2..5} gets expanded to the sequence 2 3 4 5 and your script works as you expect it to work.

When you add the same scipt to a file, however, it does not work. This is due to the shebang that you are using (#!/bin/sh), which tells your script to run in the sh shell, which is POSIX-compliant and does not support braces expansion.

So you have two options:

  1. Change the shebang to #!/bin/bash or another shell that supports brace expansion.

or

  1. Use #!/bin/sh and replace {2..5} by $(seq 2 5).

Also take a look at this interesting Stack Overflow question about the differences between sh and Bash.

Tags:

Bash

Scripts