Linux/Ubuntu Set: Illegal Option -O Pipefail

Linux/Ubuntu set: Illegal option -o pipefail

You are running bin/sh, on Ubuntu it is a symbolic link pointing to /bin/dash, but pipefail is a bashism.

Make the script executable:

chmod +x myscript.sh

and then run the script as follows:

sudo ./myscript.sh

Setting pipefail for a single piped command

From the Bash command line you would need to invoke a subshell to avoid pipefail being set afterwards:

$ (set -o pipefail && command1 | command2 | command3)

This would limit the effect of the pipefail option to the subshell create by the parentheses (...).

A real example:

$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active

If you use an explicit shell call with the -c option you do not need a subshell, either with bash or with an sh alias to bash:

$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active

Since your sh does not accept the pipefail option, I would have to assume that it is either some older or modified version of bash - or that it is actually some other shell completely.

read fails with set -eou pipefail

The read command tries to read a single line from standard input. If it fails for any reason -- including hitting the end-of-file before seeing a line terminator -- it exits with a nonzero status. In your case, the -d '' option tells read to look for an ASCII null character as the line terminator, and since the here-document doesn't have one it reads until it hits EOF... and then exits with an error status.

read's behavior may be a bit counterintuitive here. It read something successfully, and set the variable (payload) just fine; but since it hit EOF it's required by the POSIX standard to return an error. The exact same thing happens when reading a text file line-by-line, and the last line isn't terminated.

Normally this wouldn't be a big deal, but the -e option to set makes the shell exit if any simple command exits with a nonzero (error) status (with lots of messy exceptions that aren't relevant here). When read does that, the script exits on the spot.

So, there are a few possible solutions. You could just not use set -e, you could put set +e just before the read command (and maybe set -e again afterward), or you could make it a compound command that'll succeed, like this:

read -rd '' payload << EOF || true
...

(Here, the || means if the first command fails it'll run the second, and true always succeeds, so the compound command is considered to succeed.)

Bash script - check how many times public IP changes

while true  
PREV_IP=00
do

is the reason you are seeing ip each loop. It's the same as while true; PREV_IP=00; do. The exit status of true; PREV_IP=00 is the exit status of last command - the exit status of assignment is 0 (success) - so the loop will always execute. But PREV_IP will be reset to 00 each loop... This is a typo and you meant to set prev_ip once, before the loop starts.

    "$(date)" 

will try execute the output of date command, as a next command. So it will print:

$ "$(date)" 
bash: sob, 20 mar 2021, 10:57:02 CET: command not found

And finally, to silence curl, read man curl first and then find out about -s. I use -sS so errors are also visible.

Do not use uppercase variables in your scripts. Prefer lower case variables. Check you scripts with http://shellcheck.net . Quote variable expansions.

I would sleep each loop. Your script could look like this:

#!/bin/bash
prev=""
while true; do
cur=$(curl -sS https://ipinfo.io/ip)
if [ "$prev" != "$cur" ]; then
prev="$cur"
echo "$(date) $cur"
fi
sleep 1
done

that I want the output to direct to a file instead of outputting it into the terminal.

Then research how redirection works in shell and how to use it. The simplest would be to redirect echo output.

 echo "$(date) $cur" >> "a_file.txt"

The interval is currently set to 1 second for test purposes. This will change to a higher interval in the final product.

You are still limited with the time it takes to connect to https://ipinfo.io/ip. And from ipinfo.io documentation:

Free usage of our API is limited to 50,000 API requests per month.

And finally, I wrote a script where I tried to use many public services as I found ,get_ip_external for getting external ip address. You may take multiple public services for getting ipv4 address and choose a random/round-robin one so that rate-limiting don't kick that fast.

Start up script fails with error -e: invalid option , what is missing?

In your secondary script, you have this line at the end :

exec "$@"

It is very likely (well, mostly certain) that positional parameters contain -e as an argument. Where could that come from, you may ask?

Your secondary script is sourced by this line in the primary script :

. $init

Sourced scripts execute in the context of the parent, so positional parameters are not replaced (unless you specify arguments after the name of the file you are sourcing). If $1 in your parent script contains -e, your sourced script will see that. It is possible your main script is receiving an argument, or one of your secondary scripts changes arguments. It is a bit of a problem executing all these scripts in the same context, there can be variables and positional parameters leaking.

There is another issue I am seeing : your secondary script ends with an exec command, which replaces the current process with the command provided in argument (except in the specific cases where exec is used to manipulate file descriptors). Therefore, I would expect this secondary script to never return to the main script, and because of the secondary script being sourced, your primary script actually never finishing.



Related Topics



Leave a reply



Submit