0

Just a simple terminal session:

$ # the file really exists
$ [[ -e mydir/564df455-92e6-ac59-9b96-b3665f2aa3c7.vmem ]]
$ echo $?
0
$ # not with globbing though
$ [[ -e mydir/*.vmem ]]
$ echo $?
1

The wildcard * is supposed to represent any number of characters. Hm.

What am I missing?

Update

compgen works as expected:

$ compgen -G "mydir/*.vmem"; echo $?
0

However, I'd like to find out why the original attempt doesn't work. I want to learn Bash, not just get it to work and pass on. I checked: noglob is not set.

Update 2

According to @Aaron, this should (and does) work with the original test:

$ files=( mydir/*.vem )
$ [[ ${#files[@]} -gt 0 ]]; echo $?
0

This version is actually easier to write and understand in my script function (where the question came up). The whole script is for syncing vmware to a backup folder on a time machine volume.

Using compgen:

# get the status of a vm
# argument: path to the vm
# compgen exit code: 0 - path(s) found, 1 - nothing found
function vm_status() {
  local vm_path="$1"
  local status=-1
  [[ $status -lt 0 ]] && { compgen -G "$vm_path/*.vmem" > /dev/null; }      || { status=0; }  # vm is shut down:  vm does not contain file with extension .vmem
  [[ $status -lt 0 ]] && { compgen -G "$vm_path/*.vmss" > /dev/null; }      && { status=1; }  # vm is suspended:  vm contains file with extension .vmss
  [[ $status -lt 0 ]] && { compgen -G "$vm_path/*.vmem.lck" > /dev/null; }  && { status=2; }  # vm is running:    vm contains folder name ending with .vmem.lck
  echo $status  # should return 0, 1 or 2
}

Having to throw out the compgen output isn't needed with [[:

# get the status of a vm
# argument: path to the vm
function vm_status() {
  shopt -s nullglob # prevents non-matching glob from reporting one file (the glob itself)
  local vm_path="$1"
  local status=-1
  [[ $status -lt 0 ]] && { files=( "$vm_path"/*.vmem ); }      && [[ ${#files[@]} -gt 0 ]] || { status=0; }  # vm is shut down:  vm does not contain file with extension .vmem
  [[ $status -lt 0 ]] && { files=( "$vm_path"/*.vmss ); }      && [[ ${#files[@]} -gt 0 ]] && { status=1; }  # vm is suspended:  vm contains file with extension .vmss
  [[ $status -lt 0 ]] && { files=( "$vm_path"/*.vmem.lck ); }  && [[ ${#files[@]} -gt 0 ]] && { status=2; }  # vm is running:    vm contains folder name ending with .vmem.lck
  echo $status  # should return 0, 1 or 2
}
Timm
  • 2,488
  • 2
  • 22
  • 25
  • 2
    +1 for using the above duplicate, the syntax you're trying to use would fail in a number of cases. I don't know why it returned a non-zero exit code without raising an error in your current context though, unless globbing itself is turned of (`set -o noglob`) – Aaron Feb 13 '21 at 17:17
  • I suggest to replace `[[ -e mydir/*.vmem ]]` with `compgen -G mydir/*.vmem`. – Cyrus Feb 13 '21 at 17:21
  • 1
    @Cyrus I think you'd want quotes around the glob, otherwise `bash` is going to expand it rather than passing it to `compgen` as text. Might work anyway, I'm not sure how `compgen` deals with lack of argument / multiple arguments. – Aaron Feb 14 '21 at 08:54
  • @Aaron I had realized that after a while; I'll edit my update. – Timm Feb 14 '21 at 19:38
  • I don't know why, but it looks like the glob isn't expanded : https://ideone.com/MqNiYs. The conditional expression looks for a file named `*.vmem` – Aaron Feb 16 '21 at 10:24
  • 1
    Ok, this is a behaviour specific to parsing `[[ expression ]]` ; from its section in `man bash` : "Word splitting and pathname expansion are not performed on words between `[[` and `]]`". Pathname expansion is what resolves globs – Aaron Feb 18 '21 at 09:26
  • Excellent! Thanks @Aaron, I'll make a note of this in my bash tips. Yippeee! – Timm Feb 19 '21 at 11:54

0 Answers0