By syss


2019-02-11 11:10:35 8 Comments

Why is this working:

mkdir /dir/test{1,2,3}

and this not?

{chown httpd,chmod 700} /dir/test1
-bash: {chown: command not found

My Bash Version is: GNU bash, version 4.2.46(2)-release

3 comments

@ilkkachu 2019-02-11 14:17:08

Other answers have explained why the brace expansion doesn't work. Ignoring that question for a moment, you probably want to avoid repeating the filename, and there are other ways to do that. Either assign the file name to a variable, or use the $_ special variable (it contains the last shell word of the previous command):

f="some long and ugly filename"
chown httpd "$f"
chmod 700 "$f"

or

chown httpd "some long and ugly filename"
chmod 700 "$_"

@ilkkachu 2019-02-11 14:17:39

history expansion would also be an option, I just can't remember the correct expansion

@Kusalananda 2019-02-11 11:17:58

Your brace expansion is not valid. A brace expansion must be one word in the shell.

A word is a string delimited by unquoted spaces (or tabs or newlines, by default), and the string {chown httpd,chmod 700} consists of the three separate words {chmod, http,chmod and 700} and would not be recognised as a brace expansion.

Instead, the shell would interpret the line as a {chown command, executed with the arguments http,chmod, 700} and /dir/test1.

The simplest way to test this is with echo:

$ echo {chown httpd,chmod 700} /dir/test1
{chown httpd,chmod 700} /dir/test1

$ echo {"chown httpd","chmod 700"} /dir/test1
chown httpd chmod 700 /dir/test1

Note that even if your brace expansion had worked, the command would have been nonsensical.

Just write two commands,

chown http /dir/test1
chmod 700  /dir/test1

@Time4Tea 2019-02-11 11:20:25

Is it possible to achieve the effect with quoting, or would that still not work?

@Time4Tea 2019-02-11 11:21:49

Oh no, because you'd still have two commands on one line.

@Kusalananda 2019-02-11 11:23:07

@Time4Tea One command, in fact, with the wrong arguments.

@syss 2019-02-11 13:11:28

When you say "should", how would one be able to force multiple words? Or is it a "must"?

@Kusalananda 2019-02-11 13:12:46

@syss It's "must" (I will change it in the text). A brace expansion expands to a set of words. If the brace expansion itself contains spaces, then these have to be quoted, as I have shown.

@Freddy 2019-02-11 13:40:03

Another example similar to the "mkdir"-example, but with an empty expression and some whitespace is mkdir test{,2," three",\ four} (creates directories "test", "test2", "test three", "test four")

@mosvy 2019-02-11 15:13:58

If the brace expansion were performed at command line level instead of word level, that command would've made perfect sense; it just isn't and that's all that can be said about it. Simulating such a behavior with an eval: eval {'chown http','chmod 0666'}' /tmp/foo;'.

@Kusalananda 2019-02-11 15:22:54

@mosvy Yes, with eval and with very careful quoting, it would be possible to do what the user wanted.

@JoL 2019-02-11 16:29:53

@Kusalananda and wrong command name, as it'd be searching for an executable called "chown httpd" in PATH.

@Kusalananda 2019-02-11 16:31:41

@JoL I don't think so actually. You would have to quote it en extra time for that. eval {'"chown http"', ...}

@JoL 2019-02-11 16:33:07

@Kusalananda I just tried {"chown httpd","chmod 700"} /dir/test1 and got bash: chown httpd: command not found.

@Kusalananda 2019-02-11 16:33:32

@JoL You left the eval out.

@JoL 2019-02-11 16:36:10

@Kusalananda Ah. I was initially responding to your "One command [...] with the wrong arguments" comment, which responded to a discussion on simply using quotes. I hadn't seen the later discussion on eval.

@Kusalananda 2019-02-11 16:37:41

@JoL :-) that explains it. In that case, you are absolutely right.

@Sergiy Kolodyazhnyy 2019-02-11 22:12:31

Worth noting, that if the goal is to shorten the command OP has to type, they could reuse bash's history expansion to use the last command line argument as in !#:1. askubuntu.com/a/1109025/295286

@mosvy 2019-02-12 08:16:16

@Kusalananda I wasn't suggesting to use eval in this case, I was trying to illustrate what would happen in a hypothetical shell where the brace expansion is performed at command line level -- a command line would be turned into 2 or more command lines and that usage would make perfect sense. My point is that your claim that the command would've been nonsensical in any case is begging the question by already assuming a bash-like shell in which that simply doesn't work, whether sensical or nonsensical.

@mosvy 2019-02-11 11:18:25

because, as mentioned in the man page, bash will perform the brace expansion on each word after splitting a command line into words.

So, that command line will be first split into {chown, httpd,chmod and 700}, and then, since {chown is not a valid brace expansion pattern, it will be left as is and bash will try to run a command with that name.

This is the quote from the manpage:

Expansion is performed on the command line after it has been split into words. There are seven kinds of expansion performed: brace expansion, tilde expansion, parameter and variable expansion, command substitution, arithmetic expansion, word splitting, and pathname expansion.

Notice the order, which is different from other shells (in zsh, the brace expansion will be performed after the arithmetic expansion, and the extra word splitting won't be performed at all).

The following will print 1 2 in zsh or ksh, and x y in bash:

f=; f1=x; f2=y; echo $f{1,2}

@syss 2019-02-11 13:10:35

when you say "Notice the order" on the expansions performed, brace expansion comes before word splitting. And in your first line you say that brace expansion comes after word splitting. I am confused by that

@mosvy 2019-02-11 13:39:58

that's an extra word splitting which is done just before path expansion (globbing). if the a variable contains the string x y, then a command line like echo $a will be 1st split into echo and $a, then $a will be expanded into x y, and then split again into x and y, giving echo, x and y as separate arguments. The latter step will be done using the value of IFS ( not necessarily containing spaces) and does not happen in zsh.

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] Trap not working

  • 2019-06-01 12:44:03
  • prashant
  • 67 View
  • 1 Score
  • 1 Answer
  • Tags:   bash shell-script

1 Answered Questions

1 Answered Questions

[SOLVED] bash 4.3 "multiple dot" commands fails silently on Fedora

  • 2016-05-13 15:34:40
  • Emmanuel
  • 144 View
  • 7 Score
  • 1 Answer
  • Tags:   bash fedora

1 Answered Questions

[SOLVED] bash tab completion not working in >& redirection

4 Answered Questions

[SOLVED] Using chown $USER:$USER inside bash script

1 Answered Questions

[SOLVED] Deduplicating Bash Brace Expansions

2 Answered Questions

[SOLVED] Bash's declare -p HISTIGNORE brings bash to a halt! Why?

Sponsored Content