1

Please, don't take this the wrong way, but before someone answers and tells me I should use an array, I'm looking for the reason why the following code doesn't work, not 'how to do it correctly'. I've searched the internet for the reason for this.

Given in bash:

function fn1 {
  file=$HOME/$1*.cfg
  echo $file
}

touch $HOME/abc-def.cfg
fn1 abc

returns /home/user/abc*.cfg

Why doesn't the * expand to give /home/user/abc-def.cfg?

A workaround:

file=$HOME/$(ls -1 $HOME|grep $1)

is not elegant.

Background: I know there will be only one file that begins 'abc', but the rest of the filename can vary, I don't care about that, just the initial identifier (abc in the case above).

Lastly, great forum, use it a lot, but this is the first time I didn't find an answer, so my first posting - be kind :-)

DJF
  • 19
  • 2
  • You need to use `file=($HOME/$1*.cfg)` – hek2mgl Nov 19 '15 at 11:54
  • If you set [`shopt -s nullglob`](http://mywiki.wooledge.org/glob#nullglob) it works. Not very sure why, though. – fedorqui Nov 19 '15 at 12:01
  • hek2mgl - that doesn't appear to work ? – DJF Nov 19 '15 at 12:18
  • fedorqui - nor does shopt -s nullglob – DJF Nov 19 '15 at 12:19
  • should mention I'm using Cygwin, but that shouldn't matter, however, it appears to - Cygwin bash --version = `GNU bash, version 4.3.42(4)-release (x86_64-unknown-cygwin)`, on SUSE, bash --version = `GNU bash, version 3.2.51(1)-release (x86_64-suse-linux-gnu)`. so a later bash on Cygwin doesn't appear to work the same way – DJF Nov 19 '15 at 12:24
  • @DJF to refer somebody, use `@` before his/her name. Otherwise we won't get notifications. – fedorqui Nov 19 '15 at 12:25
  • Hmm. I couldn't reproduce this (i.e., the globbing worked correctly) using either Bash 4.3.33 or 4.3.42 on Cygwin or 3.2.25 on CentOS 5. I also tried using `bash --norc` in case I had an option set that would affect this behaviour. – Anthony Geoghegan Nov 19 '15 at 12:29
  • 1
    DOS line endings? `file` may end with a carriage return, meaning nothing matches. – chepner Nov 19 '15 at 12:30
  • File globbing works only if matching occurs. Does **/home/user/abc-def.cfg** really exist in the home directory? – Kadir Nov 19 '15 at 12:34
  • @DJF Are you saying it works on SUSE ? – 123 Nov 19 '15 at 13:22
  • What is the output if you change `fn1` to use `echo "$file==="` instead? – chepner Nov 19 '15 at 14:11

1 Answers1

2

Works for me.

$ function fn1 {
>   file=$HOME/$1*.cfg
>   echo $file
> }
$ 
$ touch $HOME/abc-def.cfg
$ fn1 abc
/home/jackman/abc-def.cfg

However, if I disable filename expansion, I see your results:

$ set -f
$ fn1 abc
/home/jackman/abc*.cfg

Have you done set -f beforehand? If you want to account for that in your function:

function fn1 { 
    local filename_expansion_disabled
    [[ $- == *f* ]]; filename_expansion_disabled=$?

    local file=$HOME/"$1"*.cfg

    [[ $filename_expansion_disabled -eq 0 ]] && set +f
    echo $file
    [[ $filename_expansion_disabled -eq 0 ]] && set -f || true
}

Then

$ set +f
$ fn1 abc
/home/jackman/abc-def.cfg
$ set -f
$ fn1 abc
/home/jackman/abc-def.cfg

Running the function in a subshell has the same effect, and is simpler at the expense of an insignificant performance penalty:

fn1() (
    file=$HOME/"$1"*.cfg
    set +f
    echo $file
)
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
  • brilliant, that was it, I must have disabled it beforehand and not realised it. Great code to check etc. Thank you. – DJF Nov 19 '15 at 17:19