Bash : error handling in "export" instruction - bash

I'm using bash for writing a script.
I use set -ein order to have the script exit (in error) when a line results in an error (i like this approach, that I find less error prone). I almost always combine it with set -u for also "raising" an error when it is attempted to read an undefined variable.
It has worked like a charm since a long time. But today, I found a bug in my script that I could not catch with "set -eu" before, because this does not seem to raise an error like usual.
For the following, I will use the false command that always returns an error (in my script this is another personnal command, but this makes it easier for you to reproduce).
set -eu
A=$(false)
The code above exits bash with an error. Cool this is what I expect.
BUT :
set -eu
export A=$(false)
does not raise any error, bash is totally fine with it !
It even sets the variable A with an empty string, so further reads of $A will not raise an error either !
This is really weird for me, is there a way of getting the expected behaviour, maybe another option for ```set`` ?
I can do this for having it raise an error, but I will have to write it this way every time, so it is less useful for catching bugs :
set -eu
A=$(false)
export A=$A
God bash is complicated :-)

You're not getting an error because the export itself is successful. I can't find explicit documentation of the behavior, but command substitution when building the arguments to another command seems to be one of the special cases where a non-zero exit status doesn't make set -e trigger.

Related

What does each field in a typical sh error message mean? Ex. "sh: 1: ipconfig: not found"

I have been receiving Shell error messages, typically due to a bad command, etc., but have been unable to debug the cause of these messages due to not understanding the information being provided.
I have been looking for documentation, but have been unable to find any regarding the format of an sh error message.
Example:
If I use the following command, it will fail, due to no 'ipconfig' command being available:
$ sh -c "ipconfig"
sh: 1: ipconfig: not found
What I'd like to understand is what each 'field' in that message pertains to? I assume it is:
[interpreter]: [???]: [command]: [error related to command]
I can't for the life of me determine what the number refers to, and I can't be sure if my understanding of the other fields is accurate.
Context:
I am debugging a Python2.7 pytest script used for automation testing, and there are numerous points where this script is executing shell commands. However, the output I receive is:
(32512, 'sh: 2: 2: not found')
I know that function being used to execute the shell script returns a tuple with status code and output. I know that that status code is essentially 'command not found', and the error message is also stating that. Another function is returning a string which is used for this command, and I assume what is happening is that somewhere along the way, a bad argument must have been passed and now the script is attempting to execute, what would basically be sh -c "2". I can't be sure though, as these are a lot of assumptions I'm making from a limited understanding of this error message.
If anyone could please enlighten me as to what the fields in this error ACTUALLY mean I'd be forever grateful!!

fish shell evaluate make return code

I'm trying to write a script in Fish that runs a Make recipe and then executes all of the resultant binaries. The problem I'm having is that I would like to have the script exit with an error code if the make command encounters an error. Whenever I try to capture Make's return value, I end up with its output log instead.
For example:
if test (make allUnitTests) -eq 0
echo "success"
else
echo "fail"
end
returns an error because "test" is seeing the build process, not the terminating condition.
I wrote the script so that I could easily make Jenkins run all my unit tests whenever I trigger a build. Since I haven't been able to get the above section of the script working correctly, I've instead instructed Jenkins to run the make command as a separate command, which does exactly what I want: halting the entire build process without executing any binaries if anything fails to compile. Thus, at this point my question is more of an academic exercise, but I would like to add building the unit test binaries into the script (and have it cleanly terminate on a build error) for the benefit of any humans who might check out the code and would like to run the unit tests.
I played a little with something like:
if test (count (make allUnitTests | grep "Stop")) -eq 0
but this has two problems:
I'm apparently piping stdout when I need to pipe stderr. (Come to think of it, if I could just check to see if anything was written to stderr, then I wouldn't need grep at all.)
Grep is swallowing all the log data piped to it, which I really want to be visible on the console.
You are misunderstanding the parentheses - these run a command substitution. What this does is capture the output of the process running in the substitution, which it will then use as arguments (separated by newlines by default) to the process outside.
This means your test will receive the full output of make.
What you instead want to do is just run if make allUnitTests without any parens, since you are just interested in the return value.
If you would like to do something between running make and checking its return value, the "$status" variable always contains the return value of the last command, so you can save that:
make allUnitTests
set -l makestatus $status
# Do something else
if test $makestatus -eq 0
# Do the if-thing
else
# Do the else-thing
end

Why Success is an error for bash?

Working in bash I got an error:
user#host:~$ cd ..
bash: cd: write error: Success
It happend once, and next time I tried to cd everything went fine. But I do not want this error to repeat, so I have 2 questions about this error:
Why bash tried to write something while changing dir?
And more intriguing - why Success could be an error?
Why bash tried to write something while changing dir?
Bash keeps a history of every command you run, which ultimately gets recorded in ~/.bash_history. It's likely that the attempted write was related to that.
And more intriguing - why Success could be an error?
That's a display bug. Success is not an error.
If you want the developer take on how it happens, I'm pretty confident in saying that:
bash detected an error, probably via the return code of an I/O function, and
it called the C perror() function to print an explanatory message. By the time it did so, however,
the C errno variable had been reset, if ever it had been set in the first place.
Usually such a reset of errno happens when you call another library function between calling the one that signaled the error and calling perror(). Looking at the actual error message, it is plausible that the bash implementation called sprintf() to format part of the error message, but in doing so clobbered errno.

Receiving error '__variables_definition:57: bad option: -n' when changing directory in Zsh terminal

In my zsh terminal on OSX, I receive the error __variables_definition:57: bad option: -n twice in a row whenever I use cd and when I first open the terminal. I tried Googling the error, and received no results. I'm hoping it looks familiar to someone on here. I was told to see if cd was aliased to anything, but by typing alias, it doesn't appear to be.
This doesn't seem to be causing any actual problems, it's just a slight annoyance and I'd like to know what's causing it.
It looks like the chpwd hook is set to a script with an error.
This hook is called everytime the working directory is changed. There are two ways to set this hook:
by setting defining the a function named chpwd. To check this run whence -c chpwd. It will either return the function body or "chpwd not found"
by defining an array with the name chpwd_functions, which contains a list of functions that are to be called. Run echo $chpwd_functions to get the list and then whence -c name for each name to get the function bodies (or just for func in $chpwd_functions; do whence -c $func; done to do it in one go).
Most likely here it is the second case and the culprit is a function named __variable_definition. In the 57th line of this function there is a faulty call to a command which does not know the option -n. Considering the name of the surrounding function it is probably typeset or one of its equivalents declare, float, integer, local or readonly.
You will have to look in your zsh configuration where __variable_definition is defined and fix the error there.
Note: the output of whence -c name is not always entirely identical to the definition of the function as - among other things - empty lines are removed. As the line number in the error message refers to the original definition (including empty lines) the numbering may be off compared to the output of whence -c name.

Bash For Loop Syntax Error

I am trying to perform a simple for loop, but it keeps telling me there is a syntax error near do. I have tried to find some answers online, but nothing seems to be quite answering my question.
The for loop is as so. All it wants to do is find the differences between two folders:
#!/bin/bash
for word in $LIST; do
diff DIR1/config $word/config
done
exit
The syntax error is near do. It says "Syntax error near unexpected token 'do '". $LIST is set outside of this script by the program that calls it.
Does anyone know what might be happening here?
That's certainly valid syntax for bash so I'd be checking whether you may have special characters somewhere in the file, such as CR/LF at the ends of your lines.
Assuming you're on a UNIXy system, od -xcb scriptname.sh should show you this.
In addition, you probably also want to use $word rather than just word since you'll want to evaluate the variable.
Another thing to check is that you are actually running this under bash rather than some "lesser" shell. And it's often handy to place a set -x within your script for debugging purposes as this outputs lines before executing them (use set +x to turn this feature off).
One last thing to check is that LIST is actually set to something, by doing echo "[$LIST]" before the for loop.

Resources