Re: d-i repo at dillon
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.
Reply to: