Error "tput No value for $TERM and no -T specified" - sh

I have a shell script in server A and I have a shell script in server B.
My logic is written like shell script in A gets executed and it calls a shell script in server B and executes it.
I am able to get the desired result when A executes B, but getting an error also along with the result. Error Message:
tput: No value for $TERM and no -T specified
I am using the following lines for getting output in color;
RED=`tput setaf 1`
GREEN=`tput setaf 2`
YELLOW=`tput setaf 3`
BLUE=`tput setaf 6`
BOLD=`tput bold`
RESET=`tput sgr0`
These lines are available in the shell script in both A and B.
When I execute the shell script in B by logging into server B, the desired output comes along with the color.
When I call the shell script from A and execute it, I am getting desired result plus the error message which I mentioned above.
Can you help in this regard?
FYI, I checked "echo $TERM" and output is 'xterm' in both the servers.
Not sure where I am going wrong.

My solution:
# when $TERM is empty (non-interactive shell), then expand tput with '-T xterm-256color'
[[ ${TERM}=="" ]] && TPUTTERM='-T xterm-256color' \
|| TPUTTERM=''
declare -r RES='tput${TPUTTERM} sgr0' REV='tput${TPUTTERM} rev'
declare -r fRD='tput${TPUTTERM} setaf 1' bRD='tput${TPUTTERM} setab 1'
declare -r fGN='tput${TPUTTERM} setaf 2' bGN='tput${TPUTTERM} setab 2'
...
echo ${fRD}" RED Message: ${REV} This message is RED REVERSE. "${RES}
echo ${fGN}" GREEN Message: ${REV} This message is GREEN REVERSE. "${RES}
...
This way it makes no sense if there's an interactive or a non-interactive shell - tput still works fine.

$TERM will be unset when you log in via a script. Bypass the color-coding in this scenario, or hard-code an option to tput. (I would strongly suggest the former.)
RED=; GREEN=; YELLOW=; BLUE=; BOLD=; RESET=;
case ${TERM} in
'') ;;
*)
RED=`tput setaf 1`
GREEN=`tput setaf 2`
YELLOW=`tput setaf 3`
BLUE=`tput setaf 6`
BOLD=`tput bold`
RESET=`tput sgr0`;;
esac

We supposed that the shell or environment setting are different in two servers, if possible, you can past output of next commands from the two servers.
ps
This command helps us understand what kind of shell we are using.
env
This command helps us know the environment.

I am able to fix the issue successfully now.
ssh <Server B> "TERM=xterm" <script in ServerB>
The desired output came back to ServerA with colors.

Related

How can I make a function run every time cd successfully changes to another directory within sh on FreeBSD?

I'm using sh as my shell on FreeBSD but I want to be able to have a pretty prompt like the one bash gives me on Ubuntu. There are two things that the FreeBSD implementation of sh seems to lack as far as PS1 escape characters go:
The \w works but does not expand $HOME to ~, so this is something I have already hacked up myself
I can use PS1 to update the prompt on the terminal, but as far as I can tell it is not possible to use the PS1 variable to update the title bar as well. ESC and BEL fail to set the title as one would expect if they were using bash or ksh
Here is my .shrc file
update_prompt() {
case "$PWD" in
"$HOME"*)
pretty_pwd="~${PWD#*"${HOME}"}"
;;
"/usr$HOME"*)
pretty_pwd="~${PWD#*"/usr${HOME}"}"
;;
*)
pretty_pwd="$PWD"
;;
esac
case "$TERM" in
xterm*|rxvt*)
PS1="[$USER#\\h $pretty_pwd]\\$ "
;;
*)
;;
esac
printf "\\033]0;[%s#$(hostname -s): %s]\\007" "$USER" "$pretty_pwd"
}
update_prompt
So when I fire up a terminal or log in via ssh, it gives the pretty prompt that I like. But now I need this function to run every time that cd is executed and returns an exit status of 0.
I was going to use an alias that was something like:
alias cd="cd $1 && update_prompt"
but that was before I realized that aliases do not except arguments. How might I go about doing something like this?
You can use a function instead of an alias:
cd() {
command cd "$#" && update_prompt
}
Just put it into ~/.shrc. You have to use command here to let sh know that you are referring to the actual cd builtin command instead of the function you've just defined.
Refer to the sh(1) manual page for the details on how to make sh(1) source the ~/.shrc file when it starts:
Therefore, a user should place commands that are to be executed only at login
time in the .profile file, and commands that are executed for every shell
inside the ENV file. The user can set the ENV variable to some file by placing
the following line in the file .profile in the home directory, substituting for
.shrc the filename desired:
ENV=$HOME/.shrc; export ENV
I use this trick in my cd alias manager. Here's a link to the source code of the function: https://github.com/0mp/goat/blob/v2.5.0/libgoat.sh#L31-L57
You can do it with alias+arguments if you swap the commands:
$ alias cd="echo change; cd"
$ pwd
/nas
$ cd /
change
$ pwd
/
$ cd /etc
change
$ pwd
/etc
$

Syntax error in script

My script try execute mvn clean install in all projects but before it tried switch to dev branch and pull it.
successString="[INFO] BUILD SUCCESS";
file="mvnoutput";
red=$'\e[1;31m';
grn=$'\e[1;32m';
end=$'\e[0m';
function checkResult
if grep -Fxq "$successString" $file
then
echo -en "${grn}[${1}]Build ok${end}";
else
echo "${red}[${1}]Error in mvn clean install${end}";
exit 1;
fi;
end
function pullAndSwitchDevBranch
git checkout dev;
git pull origin dev;
end
cd api-pay-commons/;
pullAndSwitchDevBranch;
touch mvnoutput;
mvn clean install -U > mvnoutput;
checkResult PAY;
Why I received this error?
line 17: end: command not found ./script.sh: line 20: syntax
error near unexpected token git' ./script.sh: line 20: git checkout dev;'
You have used the "fish" tag, so I'm assuming you are running this with the fish shell.
If so: This is not a valid fish script. Fish is explicitly not POSIX-compatible, so you might want to read up on the syntax. (If not, then please correct your tag)
red=$'\e[1;31m';
Fish does not use var=value to set a variable. It uses set var value.
Fish also does not have the $'' style of quoting. Instead, backslash-escapes are interpreted outside of quotes.
So this would be set red \e"[1;31m". Alternatively, fish offers the set_color builtin, which prints the escape sequence for a given color. So this could be set red (set_color red) (or you could call set_color later).
then
Fish does not use if condition; then dosomething; fi. It's if condition; dosomething; end.
echo -en "${grn}[${1}]Build ok${end}";
Fish does not use "${var}". It also does not call the function arguments $1 et al.
This would be something like echo -ens "$grn" "[$argv[1]]" "Build ok" "$end".
exit 1
Fish currently does not allow exiting from functions. You'll have to return 1 and check the result from the outside.
Additionally, you're using semicolons all over the place, which is not typical style in any shell I'm aware of.
In case you are not using fish, but some POSIX-compatible shell (like bash), this is also not valid. The main (and possibly only) issue is that you are using function something; dosomething; end. In bash, that would be
function something () {
#dostuff
}
And in pure POSIX, that would be
something () {
#dostuff
}

Read command output line by line in sh (no bash)

I am basically looking for a way to do this
list=$(command)
while read -r arg
do
...
done <<< "$list"
Using sh intead of bash. The code as it is doesn't run because of the last line:
syntax error: unexpected redirection
Any fixes?
Edit: I need to edit variables and access them outside the loop, so using | is not acceptable (as it creates a sub-shell with independent scope)
Edit 2: This question is NOT similar to Why does my Bash counter reset after while loop as I am not using | (as I just noticed in the last edit). I am asking for another way of achiving it. (The answers to the linked question only explain why the problem happens but do not provide any solutions that work with sh (no bash).
There's no purely syntactic way to do this in POSIX sh. You'll need to use either a temporary file for the output of the command, or a named pipe.
mkfifo output
command > output &
while read -r arg; do
...
done < output
rm output
Any reason you can't do this? Should work .. unless you are assigning any variables inside the loop that you want visible when it's done.
command |
while read -r arg
do
...
done

ksh error remove from list

I am trying to remove a certain element from a list in korn shell. It's working on my linux machine but the exact same code gives me an error on a solaris11 machine. I need a code that will work for both. It's probably because of different ksh versions but I would like to find a solution that works for both.
The code is:
#!/bin/ksh
MY_LIST="HELLO HOW ARE YOU"
toDel="HOW"
MY_LIST=( "${MY_LIST[#]/$toDel}" )
echo "MY LIST AFTER REMOVING HOW IS $MY_LIST"
On Solaris I get the following error:
syntax error at line 4 : '(' unexpected
Any suggestions?
Melodie wrote: Finally, I used 'Walter A' solution
Nice I could help.
Enabling you to vote for me and close the question, I post my comment as an answer.
MY_LIST=`echo $MY_LIST | sed "s/$toDel//"`
You'll probably need to spend some time with the ksh88 man page.
Without futher explanation:
set -A my_list HELLO HOW ARE YOU # note, separate words
toDel=HOW
set -- # using positional parameters as "temp array"
for word in "${my_list[#]}"; do
[[ $word != $toDel ]] && set -- "$#" "$word"
done
set -A my_list "$#"
printf "%s\n" "${my_list[#]}"
HELLO
ARE
YOU
Finally, I used 'Walter A' solution:
MY_LIST=`echo $MY_LIST | sed "s/$toDel//"`

bash script to build complex command syntax, print it first then execute - problems with variable expansion

I want to create scipt to faciliate producing local text file extracts from Hive.
This is to basically execute commands like below:
hive -e "SET hive.cli.print.header=true;SELECT * FROM dropme"|perl -pe 's/(?:\t|^)\KNULL(?=\t|$)//g'>extract/outbound/dropme.txt
While the above works like a charm I find it quite problematic to implement through the parametrized following script (much simplified):
#!/bin/sh
TNAME=dropme
SQL="SELECT * FROM $TNAME"
echo $SQL
echo "SQL: $SQL"
EXTRACMD="hive -e \"SET hive.cli.print.header=true;$SQL\"|perl -pe 'BEGIN{if(defined(\$_=<ARGV>)){s/\b\w+\.//g;print}}s/(?:\t|^)\KNULL(?=\t|$)//g'>extract/outbound/$TNAME.txt"
echo "CMD: $EXTRACMD";
${EXTRACMD}
When run I get: Exception in thread "main" java.lang.NumberFormatException: For input string: "e"
I know there may be many flavours you can print the text or execute command. For instance the line echo $SQL prints me list of files in the directory instead:
SELECT file1.txt file2.txt file3.txt file4.txt FROM dropme
while the next one: echo "SQL: $SQL" gives just what I want: SQL: SELECT * FROM dropme
echo "CMD: $EXTRACMD" prints the (almost) the command to be executed. Almost, as I see \t in perl code being expanded:
CMD: hive -e "SET hive.cli.print.header=true;SELECT * FROM dropme"|perl -pe 'BEGIN{if(defined($_=<ARGV>)){s\w+\.//g;print}}s/(?: |^)\KNULL(?= |$)//g'>extract/outbound/dropme.txt
Maybe that's still ok, but what I want is to be able to copy&paste this command into (other) terminal and execute as the command I put at the top. Ideally I would like that command to be exactly the same (so with \t there)
Biggest problem I have comes when I try to execute it (${EXTRACMD} line). I'm getting the error:
Exception in thread "main" java.lang.NumberFormatException: For input string: "e" …and so on, irrelevant as bash treats every 'word' as single command here. I assume as I don't even know what is really tries to run (prior print attempt obviously doesn't help)
I'm aware that I have multiple options, like:
escaping special characters in the command definition string (like I did with doublequotes)
experimenting with echo and $VAR, '$VAR' or "$VAR"
experimenting with "${EXTRACMD}" or evaluating through eval "${EXTRACMD}"
experimenting with shopt -s extglob or set -f
but as number of combinations is quite large and with my little bash experience I feel it's better to ask for good practice here so my question is:
Is there a way to print a (complex/compound shell) command first and subsequently be able to execute it (exactly as per printed output)? In this case it would be printing the exact command from the top, then executing it the same way as by manually copying that output into terminal prompt and pressing Enter.
Do not construct commands as strings. See http://mywiki.wooledge.org/BashFAQ/050 for details.
That page also talks about a built-in way of getting the shell to tell you what it is running (section 6).
If that doesn't do what you want you can also, with bash, try using printf %q\\n "${arr[*]}".