Question

When I use /bin/sh I can issue commands through bash simply by echoing to it

vagrant@vagrant:~$ sh
$ echo 'ls' | bash
some.sh

But when I try to use this command rm -rf !(cookbooks) I get this

$ echo 'rm -rf !(cookbooks)' | bash
bash: line 1: syntax error near unexpected token `('
bash: line 1: `rm -rf !(cookbooks)'

And I need issue this command from /bin/sh.

@anubhava from a packer http://www.packer.io/ provision script

if [ -d "/opt/chef/chef-solo/" ]; then
  cd /opt/chef/chef-solo
  rm -rf !(cookbooks)
fi
Was it helpful?

Solution

!(cookbooks) is an extglob. They're not enabled by default; you need to run shopt -s extglob in a prior line of bash (because the parser operates line-by-line) to make it valid.

So:

printf '%s\n' 'shopt -s extglob' 'rm -rf !(cookbooks)' | bash

...or you can enable extglobs via the command line (thanks to chepner for the addendum):

echo 'rm -rf !(cookbooks)' | bash -O extglob

By the way, it is possible to do this in POSIX sh, without use of extglobs. For instance:

# wrap in a function to have a separate $@ rather than overriding global
delete_all_but_cookbooks() {
  set --
  for f in *; do
    [ "$f" = "cookbooks" ] || set -- "$@" "$f"
  done
  rm -rf "$@"
}
delete_all_but_cookbooks

...or, much simpler, just using find:

find . -mindepth 1 -maxdepth 1 -name cookbooks -prune -o -exec rm -rf '{}' +
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top