0

1. Summary

I want to print variables from loop.

If I place echo $i after command from loop:

    Travis CI build passed.

elif I place echo $i before command from loop:

    I get exit code 1.

I don't find:

  1. why is this happening,
  2. how I can print variable before command.

2. What the script should do

I use HTMLTidy for validate my HTML.

I want, that HTMLTidy validate all HTML in folder output and subfolders of this folder.

See simply configuration of my project.

Working equivalent Windows batch script:

@echo off
FOR /R %%i IN (*.html) DO echo %%i & tidy -mq %%i

3. Steps to reproduce

I print in console:

cd output && bash ../tidy.sh

4. exit code 0

If tidy.sh:

shopt -s globstar
for i in **/*.html; do
    tidy -mq $i
    echo $i
done

Travis CI build passed:

$ cd output && bash ../tidy.sh
line 8 column 9 - Warning: trimming empty <span>
SashaInFolder.html
line 8 column 9 - Warning: trimming empty <div>
subfolder/SashaInSubFolder.html
The command "cd output && bash ../tidy.sh" exited with 0.
Done. Your build exited with 0.

5. exit code 1

Elif:

shopt -s globstar
for i in **/*.html; do
    echo $i
    tidy -mq $i
done

Travis CI build failed:

$ cd output && bash ../tidy.sh
SashaInFolder.html
line 8 column 9 - Warning: trimming empty <span>
subfolder/SashaInSubFolder.html
line 8 column 9 - Warning: trimming empty <div>
The command "cd output && bash ../tidy.sh" exited with 1.
Done. Your build exited with 1.

6. Not helped

  1. I try printf instead of echo → I get same behavior.
  2. I can't find answer to my question in Google.
1
  • It would appear tidy is the one exiting with 1. You could look into using tidy -mq "$i" || echo "tidy failed with $? on $i", in place of your current tidy command. It might help to explicitly exit 0 reaching the end of your script.
    – SYN
    Commented Mar 4, 2018 at 9:13

1 Answer 1

2

The exit status of a for loop compound command is that of the last command executed in it¹.

for cmd in true false; do
  "$cmd"
done

Returns false (a non-zero exit status) because false was the last command run.

echo will return true as long as it successfully manages to write what we're telling it to.

If you want to return false/failure if any of the tidy command fails, you'd need to either record the failure, or exit upon the first failure:

#! /bin/bash -
shopt -s globstar
ok=true
for i in ./**/*.html; do
  if tidy -mq "$i"; then
    printf '%s\n' "$i"
  else
    ok=false
  fi
done
"$ok"

or:

#! /bin/bash -
shopt -s globstar
for i in ./**/*.html; do
  tidy -mq "$i" || exit # if tidy fails
  printf '%s\n' "$i"
done

That one could still return false/failure if printf fails (for instance, when stdout is to a file on a filesystem that is full).

If you want to ignore any error and your script to return true/success in any case, just add a true or exit 0 at the end of your script.


¹ at least for the body part. For for i in $(exit 42); do :; done, most shells return 0 (AT&T ksh being the exception). They all return 0 for for i in; do :; done < "$(echo /dev/null; exit 42)".

4
  • Regarding the paragraph about ignoring errors: Using exit will be more efficient than true, since exit is builtin to the shell, but true will need to spawn a process. Even quicker would be a simple no-op (:) ! Commented Mar 6, 2018 at 18:08
  • @user1404316, true is a built-in in all modern Bourne-like shells including bash, just like : and exit (well those are special builtins, but that makes no difference in that regard). And true and false are the commands to express boolean values there. Commented Mar 6, 2018 at 19:30
  • @StéphaneChazelas : I just now double-checked and get conflicting indications in bash version 4.4.12. man builtins does not include true in the synopsis at the beginning of the page, or anywhere else. OTOH, type true does indicate that it is a shell builtin. Maybe a documentation bug. man bash also does not document true. Commented Mar 6, 2018 at 19:43
  • @user1404316, true/false builtins were added in bash-2.0 (96) and zsh-2.0 (91). ksh always had them, though initially (including in ksh86) true was defined as a builtin alias for ":" and false for "let 0". ash originally had true but not false (added later in the 90s on the various BSDs). Commented Mar 6, 2018 at 20:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .