On Sat, 2018-06-16 at 08:36 +0200, Holger Wansing wrote: > > The original/final lines are a bit strange, though, instead of having: > > > > if $($git foo bar); then … fi > > > > I suppose it should only be: > > > > if $git foo bar; then … fi > > However, with this simplified variant it fails. So I left it as is for now.
It seems there is an interesting (and new to me, or at least I'd never fully appreciated the behaviour) corner case of the `if $(foo); then` syntax, which is that if `foo` exits producing no output then its exit code is apparently used for the condition. If `foo` does produce output then the shell will attempt to execute that and use the resulting exit code. These just run true or false and take the output: $ dash -c 'if true ; then echo YES ; else echo NO ; fi' YES $ dash -c 'if false ; then echo YES ; else echo NO ; fi' NO These run true or false, see the output is "" and so use the exit code: $ dash -c 'if $(true) ; then echo YES ; else echo NO ; fi' YES $ dash -c 'if $(false) ; then echo YES ; else echo NO ; fi' NO These run `echo` (which always succeeds) then runs the resulting "true" or "false" and uses the exit code: $ dash -c 'if $(echo true) ; then echo YES ; else echo NO ; fi' YES $ dash -c 'if $(echo false) ; then echo YES ; else echo NO ; fi' NO This runs `echo` (which always succeeds) then tries to run the resulting "foo" and fails because that isn't a command: $ dash -c 'if $(echo bar) ; then echo YES ; else echo NO ; fi' dash: 1: bar: not found NO `git status` outputs nothing when the tree is clean, and I think the `$($git status -s -uno $DI_COPY/packages/po)` case uses that to succeed on a clean tree, however if the tree was dirty you'd get the "not found" stuff for something relating to the output. $ git status -s -uno build/Makefile $ echo $? 0 $ dash -c 'if $(git status -s -uno build/Makefile ) ; then echo CLEAN ; else echo DIRTY ; fi' CLEAN $ echo "FOO" >> build/Makefile $ git status -s -uno build/Makefile M build/Makefile $ echo $? 0 $ dash -c 'if $(git status -s -uno build/Makefile ) ; then echo CLEAN ; else echo DIRTY ; fi' dash: 1: M: not found DIRTY Notice that the original svn version had a `| grep -q ^C` which was checking if any line started with a "C" (for Changed I suppose), produced no output (`-q`) but exited with an error code reflecting the presence of any lines. You could do something similar but you'd need to check for more than M (modified) since git status has a variety of error codes, including (A)dded, (D)eleted, (R)enamed etc. `git status` doesn't seem to have an option which makes the error code reflect the dirtiness. In the past I've used: # Update cache, otherwise files which have an updated # timestamp but no actual changes are marked as changes # because `git diff-index` only uses the `lstat` result and # not the actual file contents. Running `git update-index # --refresh` updates the cache. git update-index -q --refresh if git diff-index --quiet HEAD -- path/to/something ; then clean ; else dirty ; fi (--quiet enable --exit-code which makes the exit status meaningful). For perhaps less git magic you could also just write it as: if [ -z "$(git status -s -uno path/to/something)" ] ; then clean ; else dirty ; fi or inversely: if [ -n "$(git status -s -uno path/to/something)" ] ; then dirty ; else clean ; fi These explicitly check whether the output of the status command was empty (the -z check, meaning clean) or non-empty (the -n check, meaning dirty). Ian.