I have a small function in a bash script like this,
func()
{
local nice_val="$NICE -n -19"
/* bunch of if/else statements and some loops*/
$nice_val $NOHUP a.out >> $log_file 2>&1 &
}
when i try to execute this file, i see this error. /root/bringup.sh: line 323: /usr/bin/nice -n -19: No such file or directory
Here are a few things i verified,
- Yes, nice executable exits in /usr/bin/nice
- my $PATH also contains /usr/bin/
- checked if i'm missing any libs, i dont think i am.
root@dg:~# ldd /usr/bin/nice
linux-vdso.so.1 (0x00007ffdc4dab000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f749b9bf000)
/lib64/ld-linux-x86-64.so.2 (0x00007f749bf67000)
root@dg:~# find / -name libc.so.6
/lib/x86_64-linux-gnu/libc.so.6
Note: 1.I'm running everything as root and $NICE, $NOHUP are some of the shell variables that gets sourced (using "source") in the beginning of the script. 2.This script gets called by another script 3.I read online clearing the hash (hash -r) might help if my "nice" was moved around but did not help. 4. All of this scripts are run inside of a container. But i guess that should not impact anything.
In the above snippet, if i replace $nice_val with the complete path to "nice", it works.
i.e
/usr/bin/nice -n -19 $NOHUP a.out >> $log_file 2>&1 &
---> Surprisingly this works.
Oh, and i checked if i have any extra spaces, /r's. I don't see any of that.
I really cant wrap my head around what's going wrong. Any insight into this problem is very much appreciated. Thanks so much.
UPDATE: This was the problem with my code: (This is a condensed dummy code that reproduces the issue) File 1: bringup.sh
#! /bin/bash
declare -r NOHUP="/usr/bin/nohup"
declare -r NICE="/usr/bin/nice"
declare -r CAT="/bin/cat"
log_file="/root/affinity/dumplog"
values_file="/root/affinity/values"
niceval="$NICE -n -10"
get_indexed_val()
{
local val=$1
if [ -e $values_file ]; then
local val_str=$($CAT $values_file)
IFS=','
read -ra cpu_array <<< "$val_str"
#
# If you uncomment the below line(setting back the IFS to 'space', code works fine.
#
#IFS=' '
return ${cpu_array[$val]}
fi
return 0
}
index=0
for (( index=0; index < 4; index++ )); do
get_indexed_val $index
myval=$?
$niceval $NOHUP /root/affinity/loop.sh $myval >> $log_file 2>&1 &
done
File 2: loop.sh
#! /bin/bash
i=0
number=$1
while [ $i -lt $number ]; do
sleep 0.1
done
File 3: values
140,150,160,170
The error message you'll see if you dont reset the IFS.
./bringup.sh: line 28: /usr/bin/nice -n -10: No such file or directory
./bringup.sh: line 28: /usr/bin/nice -n -10: No such file or directory
./bringup.sh: line 28: /usr/bin/nice -n -10: No such file or directory
./bringup.sh: line 28: /usr/bin/nice -n -10: No such file or directory
Thank you all. Much appreciated.
The error message you're getting,
/root/bringup.sh: line 323: /usr/bin/nice -n -19: No such file or directory
, indicates that "-n -19
" is being treated as part of the filename, rather than as parameters. Since there's no file named "nice -n -19
" in the /usr/bin directory, you get a file not found error.Normally, when you expand a variable that contains spaces (or other whitespace) and don't have double-quotes around it, the variable's value will be split into "words" based on whitespace. In this case, I'd expect it to be split into "
/usr/bin/nice
", "-n
", and "-19
", and so the first would be treated as the command/filename to run and the others as parameters. But in this case the splitting is apparently not happening. I see several possible explanations:IFS
has been changed. TheIFS
variable defines which characters are considered whitespace for word-splitting purposes; if it doesn't contain the space character, that would explain why the value isn't getting split normally.Changing
IFS
can have a lot of weird effects like this, so if you need to change it for some reason, it's best to set it back to normal as soon as possible afterward.It's also sometimes sufficient to apply an
IFS
change only to a single command, by making the setting a prefix to that command. For example:will split fields on commas, but since the
IFS
setting applies specifically to that command it's not necessary to set it back afterward. But this doesn't always do what you expect, because the setting applies to the execution of that command, not to how its arguments are parsed. For example,IFS=, echo $var
will split the value of$var
on normal whitespace, and then setIFS
whileecho
prints the results (so the setting has no actual effect).Those characters in the string might not be normal spaces, but something similar-looking-but-different, like non-breaking spaces. You can check by doing a hex dump of the text. Here's an example (with ^^s added by me):
See how the second dump has "c2 a0" instead of "20" in the hex, and ".." instead of just " " in the text on the right? Those are non-breaking spaces in UTF-8 encoding. Try putting
echo "$nice_val" | xxd
in your script, and see what it prints.The script is running under zsh (rather than bash). By default, zsh doesn't do word-splitting (because it actually causes a lot of bugs and there are usually better ways to do what's needed).
You actually have double-quotes around the variable reference, and just didn't include them in the question. If this were the actual command:
...then the error message would make perfect sense. Note that normally, putting double-quotes around variable references is a good idea (to avoid the problems word-splitting can filename globbing can cause), but in this case you're counting on it.
But storing commands in variables like this is somewhat unreliable anyway (see BashFAQ #50: I'm trying to put a command in a variable, but the complex cases always fail!). It might be better to define functions instead of variables for your
NICE
andNOHUP
"commands". Something like this: