coloring terminal with shell script - linux

Someone can explain me why when I copy and paste the following command in the terminal it displays the colorful test correctly, but when I run it via sh myscript.sh it does not display the colored text?
blue='\e[1;34m'
NC='\e[0m'
echo -e "${blue}Test${NC}"
EDIT
Sudo is not the problem. If I copy the above and paste directly into the terminal, everything works. If you run through file, sh myscript.sh not work

Probably because sh isn't bash on your system.
$ file /bin/sh
/bin/sh: symbolic link to `dash'
Try
bash myscript.sh

Your interactive shell seems to be GNU Bash, while sh is a generic POSIX shell, which actually may be dash, busybox sh or something else. The problem is that neither -e option for echo nor \e are POSIX-compliant.
But you can easily use printf instead of echo -e (do not forget to explicitly specify newline character \n) and \033 instead of \e:
blue='\033[1;34m'
NC='\033[0m'
printf "${blue}%s${NC}\n" 'Test'
Or, of course, you can just use bash (as Elliott Frisch suggested) if you are sure that it would be available on target system.
Also I should point out, that what you done is not right way to run shell scripts at all. If you’re writing a standalone script, then you’d better to use hashbang and set execution bit to file.
$ cat myscript
#!/bin/sh
blue='\033[1;34m'
NC='\033[0m'
printf "${blue}%s${NC}\n" 'Test'
$ chmod +x myscript
$ ./myscript
But if you’re writing a command sequence (a macros, if you will) for interactive shell, there is source (or simply .) command:
$ source myscript
(Then all of above about POSIX-compliance does not matter of course.)

Related

Wrong BASH-Variable return from a bash script

I'd like to check the value of $HISTFILE (or any similar BASH-Variable) by a bash script. On the command console 'echo $HISTFILE' is the way I normally go, but from inside a bash script, which only includes:
#!/bin/bash
echo $HISTFILE
gives an empty line instead of showing $HOME/$USER/.bash_history (or similar return values). My questions are:
What is the reason for doing so (since I never had such trouble using bash scripts) and
how can I check the value of BASH-Variables like $HISTFILE from inside a bash script?
Many thanks in advance. Cheers, M.
HISTFILE is only set in interactive shells; scripts run in non-interactive shells. Compare
$ bash -c 'echo $HISTFILE' # non-interactive, no output
$ bash -ic 'echo $HISTFILE' # interactive, produces output
/home/me/.bash_history
However, forcing the script to run in an interactive shell will also cause your .bashrc file to be sourced, which may or may not be desirable.

Writing a Script to execute commands?

I have never written a script, so bear with me. What I need to do, is make two scripts that I can click on from the desktop, will both open their own terminal (And stay open until I manually close it) and run the given lines.
For the first one, I have to manually run this:
cd home/pi/PiBits/ServoBlaster/user
sudo ./servod
For the second:
cd ~/scratchClient
python crs/scratchClient.py -c servoblaster
How would I do this? I read a few things about putting xterm -e and such in front of it, but none of that works for me...
By the way, this will be used on Raspbian Linux.
EDIT, this worked for me:
Link: ubuntuforums.org/showthread.php?t=1336228 The line that was used: gnome-terminal --execute bash -c "/path/scriptname ; bash"
You just need to add a shebang, which means putting this in the first line of the script:
#!/bin/sh
This causes the bourne shell to be used to interpret the script, this is (probably) the same interpreter that runs when you are in your terminal. Then you should make the script executable chmod +x <script>
Try this.
xterm -hold -e 'cd /home/pi/PiBits/ServoBlaster/user
sudo ./servod' &
and
xterm -hold -e 'cd /home/pi/scratchClient
python crs/scratchClient.py -c servoblaster' &
If it doesn't work, perhaps you should explain in what way this fails. If it works, you can add a shebang in front, save them in files, chmod +x those files, and click away to your heart's content (or perhaps acquire a more sophisticated taste where you simply run these as background jobs without any xterm or other anxious GUI).
Solution was to use gnome-terminal... Found an UbuntuForums post with a similar question such as mine.
gnome-terminal --execute bash -c "/path/scriptname ; bash"

Escape newline character in heredoc on solaris

I am using bash and this works on Linux:
read -r -d '' VAR<<-EOF
Hello\nWorld
EOF
echo $VAR > trail
i.e the contents of the file on Linux is
Hello\nWorld
When i run on Solaris
trial file has
Hello
World
The newline(\n) is being replaced with a newline. How can i avoid it?
Is it a problem with heredoc or the echo command?
[UPDATE]
Based on the explanation provided here:
echo -E $VAR > trail
worked fine on Solaris.
The problem is with echo. Behavior is defined in POSIX, where interpretting \n is part of XSI but not basic POSIX itself.
You can avoid this on all platforms using printf (which is good practice anyways):
printf "%s\n" "$VAR"
This is not a problem for bash by the way. If you had used #!/usr/bin/env bash as the shebang (and also not run the script with sh script), behavior would have been consistent.
If you use #!/bin/sh, you'll get whichever shell the system uses as a default, with varying behaviors like this.
To complement #that other guy's helpful answer:
Even when it is bash executing your script, there are several ways in which the observed behavior - echo by default interpreting escape sequences such as \n - can come about:
shopt -s xpg_echo could be in effect, which makes the echo builtin interpret \ escape sequences by default.
enable -n echo could be in effect, which disables the echo builtin and runs the external executable by default - and that executable's behavior is platform-dependent.
These options are normally NOT inherited when you run a script, but there are still ways in which they could take effect:
If your interactive initialization files (e.g., ~/.bashrc) contain commands such as the above and you source (.) your script from an interactive shell.
When not sourcing your script: If your environment contains a BASH_ENV variable that points to a script, that script is sourced before your script runs; thus, if that script contains commands such as the above, they will affect your script.

How to echo line with multiple quotes/special characters into file?

I am trying to echo the following line into a .profile but it keeps getting confused by either the many quotes or special characters.
bind '"e[A": history-search-backward'
I've tried all sorts of things but can't get it nailed.
This is what I currently have:
sudo su -c 'echo "bind \'\"\\e[A\": history-search-backward\'" >> /etc/profile' -
This is what it returns:
su: user '"\e[A": does not exist
Yet if I just use:
echo bind \'\"\\e[A\": history-search-backward\'" >> /home/user/testfile
It works just fine.
I have all manner of "sudo su -c "echo blah..." in the rest of my script that work just fine.
Any ideas?
Try this
sudo su -c $'echo \"bind \'\"\\e[A\": history-search-backward\'\" >> /etc/profile\' -'
From the bash man page:
A single quote may not occur between single quotes, even when preceded by a backslash.
Text quoted by $'...' may contain backslash-escaped quotes, both single and double.
Another option is to add a simpler expression to ~/.inputrc:
echo '"\e[A": history-search-backward' >> ~/.inputrc
There doesn't seem to be a system-wide equivalent of .inputrc that is read by all users. Also, this makes the key binding available to any program that uses readline. If you really do want to restrict it to bash, add a conditional expression:
cat >> ~/.inputrc <<'EOF'
$if Bash
"\e[A": history-search-backward
$endif
EOF
Every character is interpreted literally between single quotes, except ' itself. So you can put a single quote inside a literal string like this: 'single'\''quoted' is the string single'quoted.
Your command is complicated because there are two shells involved: the shell you're running this command from, and the shell that su runs. Note that it's weird to run sudo su since sudo already runs the specified command as root; sudo sh -c … makes more sense. So you need to quote for both. It's usually clearest to use single quotes for the outer shell, and double quotes or single quotes or backslashes for the inner shell.
There's another problem with your command: you're targeting the wrong file. /etc/profile is only read by login shells, whereas the bind command is specific to bash but should be read by all instances of bash, not just login shells. Instead of writing this line to /etc/profile, you should write it to the system-wide bashrc, if there is one (it's usually /etc/bash.bashrc).
sudo sh -c 'echo "bind '\''\"\\e[A\": history-search-backward'\''" >>/etc/bash.bashrc'
You may put this setting directly into the readline configuration file, /etc/inputrc. You'll save on a level of quoting.
sudo sh -c 'echo '\''"\e[A": history-search-backward'\'' >>/etc/inputrc'
An easier way to pass an arbitrary string to a command would be to pass it as input instead of as an argument and use a here document.
sudo sh -c 'cat >>/etc/inputrc' <<'EOF'
"\e[A": history-search-backward
EOF

Avoid gnome-terminal close after script execution?

I created a bash script that opens several gnome-terminals, connect to classroom computers via ssh and run a script.
How can I avoid that the gnome-terminal closes after the script is finished? Note that I also want to be able to enter further commands in the terminal.
Here is an example of my code:
gnome-terminal -e "ssh root#<ip> cd /tmp && ls"
As I understand you want gnome-terminal to open, have it execute some commands, and then drop to the prompt so you can enter some more commands. Gnome-terminal is not designed for this use case, but there are workarounds:
Let gnome-terminal run bash and tell bash to run your commands and then start a new bash
$ gnome-terminal -- bash -c "echo foo; echo bar; exec bash"
or if the commands are in a script
$ gnome-terminal -- bash -c "./scripttorun; exec bash"
The first bash will terminate once all the commands are done. But the last command is a new bash which will then just keep running. And since something is still running gnome-terminal will not close.
Let gnome-terminal run bash with a prepared rcfile which runs your commands
Prepare somercfile:
source ~/.bashrc
echo foo
echo bar
Then run:
$ gnome-terminal -- bash --rcfile somercfile
bash will stay open after running somercfile.
i must admit i do not understand completely why --rcfile has this behaviour but it does.
Let gnome-terminal run a script which runs your commands and then drops to bash
Prepare scripttobash:
#!/bin/sh
echo foo
echo bar
exec bash
Set this file as executable.
Then run:
$ gnome-terminal -- ./scripttobash
for completeness
if you just want to be able read the output of the command and need no interactivity
go to preferences (hamburger button -> preferences)
go to profiles (standard or create a new one)
go to command tab
when command exits -> hold the terminal open
i recommend to create a new profile for just for this use case.
use the profile like this:
gnome-terminal --profile=holdopen -- ./scripttorun
Every method has it's quirks. You must choose, but choose wisely.
I like the first solution. it does not need extra files or profiles. and the command says what it does: run commands then run bash again.
All that said, since you used ssh in your example, you might want to take a look at pssh (parallel ssh). here an article: https://www.cyberciti.biz/cloud-computing/how-to-use-pssh-parallel-ssh-program-on-linux-unix/
Finally this one works for me:
gnome-terminal --working-directory=WORK_DIR -x bash -c "COMMAND; bash"
Stack Overflow answer: the terminal closes when the command run inside it has finished, so you need to write a command that doesn't terminate immediately. For example, to leave the terminal window open until you press Enter in it:
gnome-terminal -e "ssh host 'cd /tmp && ls'; read line"
Super User answer: Create a profile in which the preference “Title and Command/When command exits” is set to “Hold the terminal open”. Invoke gnome-terminal with the --window-with-profile or --tab-with-profile option to specify the terminal name.
Run with -ic instead -i to make terminal close bash proccess when you close your terminal gui:
gnome-terminal -e "bash -ic \"echo foo; echo bar; exec bash\""
As of January 2020, the -e option in gnome-terminal still runs properly but throws out the following warning:
For -e:
# Option “-e” is deprecated and might be removed in a later version
of gnome-terminal.
# Use “-- ” to terminate the options and put the command line to
execute after it.
Based on that information above, I confirmed that you can run the following two commands without receiving any warning messages:
$ gnome-terminal -- "./scripttobash"
$ gnome-terminal -- "./genericscripttobash \"echo foo\" \"echo bar\""
I hope this helps anyone else presently having this issue :)
The ideal solution would be to ask for a user input with echo "Press any key".
But if double-click in Nautis or Nemo and select run in a terminal, it doesn't seem to work.
In case of Ubuntu a shell designed for fast start-up and execution with only standard features is used, named dash I believe.
Because of this the shebang is the very first line to start with to enable proper use of bash features.
Normally this would be: #!/bin/bash or similar.
In Ubuntu I learned this should be: #!/usr/bin/env bash.
Many workarounds exist to keep hold of the screen before the interpreter sees a syntax error in a bash command.
The solution in Ubuntu that worked for me:
#!/usr/bin/env bash
your code
echo Press a key...
read -n1
For a solution applicable to any terminal, there is a script that opens a terminal, runs the command specified and gives you back the prompt in that new terminal:
https://stackoverflow.com/a/60732147/1272994
I really like the bash --rcfile method
I just source ~/.bashrc then add the commands I want to the new startrc.sh
now my automated start.sh work environment is complete... for now 😼
If running a bash script just add gedit afile to the end of the script and that will hold gnome-terminal open. "afile" could be a build log which it was in my case.
Did not try just using gedit alone but, that would properly work too.
Use nohup command.
nohup gnome-terminal -e "ssh root# cd /tmp && ls"
Hope this will help you.

Resources