Simple if statement in bash doesn't work - bash

I am learning a little bit of bash in Linux and I just can't understand why this doesn't work. It is a simple IF statement and a read command to keep the window opened. What happens is that when I execute the .sh file the terminal's window opens for a second and closes back. I can't see any message or check whether there's any error or why it doesn't work. If I remove the IF block then I can see the message and the window remains opened. This is the code inside my file
count=99
if [ $count -eq 100 ]; then
echo "Count is 100"
else
echo "Count is not 100"
fi
read -p "Press enter to continue" nothing
I tried many other ways of using the IF structure but seems like none works

Use the dos2unix utility to convert the text file created on Windows to the correct format for Linux. See this wikipedia page for more details.
Install if necessary:
$ sudo apt-get install dos2unix
<snip>
Setting up dos2unix (5.3.1-1) ...
$
Run it on your script:
$ dos2unix if.sh
dos2unix: converting file if.sh to Unix format ...
$

Your script is completely correct. atleast its okai in my linux mint

Related

How to run shell script as a client side hook script for tortoiseSVN?

I have written the shell script and i am trying to put that script as a client side hook script but not getting the script engine which one i should be using to run .sh file.Usually as i have seen .js file will be used as hook script for SVN unfortunately i don't know much about jscript so please help me how to add and run the script in SVN as client side hook script.I have tried using WScipt and CScirpt but both of them are not working for my shell script.
#!/bin/bash
MAIN_DIR="/cygdrive/e/Trunk/COMMON"
FILE_NAME="/cygdrive/e/Trunk_PRE_COMMIT_HOOK/long_path.txt"
lengthy_path=`find ${MAIN_DIR} -regextype posix-extended -regex '.{500,}'| awk -F'Trunk/' '{print $2}' > ${FILE_NAME}`
if [ -f ${FILE_NAME} ]
then
if [ -s ${FILE_NAME} ]
then
echo -e "\n\n\nSorry the path of a file exceeds 256 charectors, please make it shorten and try commiting again.You can see the path in $FILE_NAME"
else
echo -e "\n\n\nPath is perfect code can be committed..........."
fi
else
echo -e "\n\n\nFile not exists............"
fi
You're trying to execute a bash script on Windows, which means you either need Cygwin installed or can use the new bash shell functionality in Windows 10. I have little experience with either, but hopefully I can get you pointed in the right direction.
If you're using Cygwin, use the following command in the Tortoise hook script configuration dialog (Fig. 4.87 in the documentation):
C:\cygwin\bin\bash C:\path\to\your_script.sh
(Sourced from this answer)
If you're using the Windows 10 bash shell, use this command:
bash -c "/mnt/c/path/to/your_script.sh"
(Sourced from this page under "Run Linux Commands From Outside Bash")
Disclaimer: I haven't tested either of these because I don't have the time or means. Try it out, and leave some feedback either way.

Pipe Code to sh — Script not waiting on read Command

Content of my remote file:
#!/bin/sh
read foo && echo "$foo"
What I’m doing locally in my terminal:
$ curl -fLSs http://example.com/my-remote-file.sh | sh
What I’m expecting:
The downloaded script should prompt the user to enter something and wait for the users input.
What actually happens:
The downloaded script skips the read command and continues executing.
Question:
How can I prompt the user to input something from a script that is downloaded via curl? I know that sh <(curl -fLSs http://example.com/my-remote-file.sh) is working, but this is not POSIX compliant and I’d like to achieve that.
The problem is that stdin is reading from curl, rather than the keyboard. You need to change your script to instruct it to read specifically from the terminal, like this:
read input < /dev/tty
echo $input

Why isn't this command returning to shell after &?

In Ubuntu 14.04, I created the following bash script:
flock -nx "$1" xdg-open "$1" &
The idea is to lock the file specified in $1 (flock), then open it in my usual editor (xdg-open), and finally return to prompt, so I can open other files in sequence (&).
However, the & isn't working as expected. I need to press Enter to make the shell prompt appear again. In simpler constructs, such as
gedit test.txt &
it works as it should, returning the prompt immediately. I think it has to do with the existence of two commands in the first line. What am I doing wrong, please?
EDIT
The prompt is actually there, but it is somehow "hidden". If I issue the command
sudo ./edit error.php
it replies with
Warning: unknown mime-type for "error.php" -- using "application/octet-stream"
Error: no "view" mailcap rules found for type "application/octet-stream"
Opening "error.php" with Geany (application/x-php)
__
The errors above are not related to the question. But instead of __ I see nothing. I know the prompt is there because I can issue other commands, like ls, and they work. But the question remains: WHY the prompt is hidden? And how can I make it show normally?
Why isn't this command returning to shell after &?
It is.
You're running a command in the background. The shell prints a new prompt as soon as the command is launched, without waiting for it to finish.
According to your latest comment, the background command is printing some message to your screen. A simple example of the same thing:
$ echo hello &
$ hello
The cursor is left at the beginning of the line after the $ hello.
As far as the shell is concerned, it's printed a prompt and is waiting a new command. It doesn't know or care that a background process has messed up your display.
One solution is to redirect the command's output to somewhere other than your screen, either to a file or to /dev/null. If it's an error message, you'll probably have to redirect both stdout and `stderr.
flock -nx "$1" xdg-open "$1" >/dev/null 2>&1 &
(This assumes you don't care about the content of the message.)
Another option, pointed out in a comment by alvits, is to sleep for a second or so after executing the command, so the message appears followed by the next shell prompt. The sleep command is executed in the foreground, delaying the printing of the next prompt. A simple example:
$ echo hello & sleep 1
hello
[1] + Done echo hello
$
or for your example:
flock -nx "$1" xdg-open "$1" & sleep 1
This assumes that the error message is printed in the first second. That's probably a valid assumption for you example, but it might not be in general.
I don't think the command is doing what you think it does.
Have you tried to run it twice to see if the lock cannot be obtained the second time.
Well, if you do it, you will see that it doesn't fail because xdg-open is forking to exec the editor. Also if it fails you expect some indication.
You should use something like this
flock -nx "$1" -c "gedit '$1' &" || { echo "ERROR"; exit 1; }

Send keystroke to Dockerfile, Ubuntu

I'm creating Dockerfile script and it has a command line that executes a program and requires user input 1 from keyboard as selected option to go to further steps.
Xdotool, man yes or expect cannot help in this situation.
Update source-code:
First off, download and extract RevoMath library, navigate to RevoMath folder then execute the install script.
...
RUN wget -q https://mran.microsoft.com/install/mro/3.2.4/RevoMath-3.2.4.tar.gz
RUN tar -xzf RevoMath-3.2.4.tar.gz
RUN cd RevoMath/
RUN ./RevoMath.sh
...
Install script has some select options as follow:
echo "1. Install MKL"
echo "2. Uninstall MKL"
echo "3. Exit utility"
We need to enter 1 from keyboard to install. How can we do it via Docker command?
Any help would be appreciated!
If I correctly understand you, you would like to add echo 1 | before ./RevoMath.sh in your Dockerfile:
...
RUN cd RevoMath/ && echo 1 | ./RevoMath.sh
...
BTW: In your example this lines will not work as you expected:
RUN cd RevoMath/
RUN ./RevoMath.sh
Because each RUN is an independent execution.
You should use && if you want to execute RevoMath.sh script from specific folder (see my example in the beginning)
I suggest to use redirect from standard input.
For example install.sh required some input(s) from user at execution time.
Suppose you need to enter 1 as a response to first interaction(questions) and
then you have another response as y for further interaction then it's good to use redirect from stdin.
$#>install.sh <EOF
$#>1
$#>y
$#>EOF
This way whenever script is waiting for inputs it will answer as 1 for the first question and y for the second question.

How can I start an ssh session with a script without redirecting stdin?

I have a series of bash commands, some with interactive prompts, that I need run on a remote machine. I have to have them called in a certain order for different scenarios, so I've been trying to make a bash script to automate the process for me. However, it seems like every way to start an ssh session with a bash script results in the the redirection of stdin to whatever string or file was used to initiate the script in the first place.
Is there a way I can specify that a certain script be executed on a remote machine, but also forward stdin through ssh to the local machine to enable the user to interact with any prompts?
Here's a list of requirements I have to clarify what I'm trying to do.
Run a script on a remote machine.
Somewhere in the middle of that remote script be command that will prompt for input. Example: git commit will bring up vim.
If that command is git commit and it brings up vim, the user should be able to interact with vim as if it was running locally on their machine.
If that command prompts for a [y/n] response, the user should be able to input their answer.
After the user enters the necessary information—by quitting vim or pressing return on a prompt—the script should continue to run like normal.
My script will then terminate the ssh session. The end product is that commands were executed for the user without them needing to be aware that it was through a remote connection.
I've been testing various different methods with the following script that I want run on the remote machine.
#!/bin/bash
echo hello
vim
echo goodbye
exit
It's crucial that the user be able to use vim, and then, when the user finishes, "goodbye" should be printed to the screen and the remote session should be terminated.
I've tried uploading a temporary script to the remote machine and then running ssh user#host bash /tmp/myScript, but that seems to also take over stdin completely, rendering it impossible to let the user respond to prompts for user input. I've tried adding the -t and -T options (I'm not sure if they're different), but I still get the same result.
One commenter mentioned using expect, spawn, and interact, but I'm not sure how to use those tools together to get my desired behavior. It seems like interact will result in the user gaining control over stdin, but then there's no way to have it relinquished once the user quits vim in order to let my script continue execution.
Is my desired behavior even possible?
Ok, I think I've found my problem. I was creating a wrapper script for ssh that looked like this:
#!/bin/bash
tempScript="/tmp/myScript"
remote=user#host
commands=$(</dev/stdin)
cat <(echo "$commands") | ssh $remote "cat > $tempScript && chmod +x $tempScript" &&
ssh -t $remote $tempScript
errorCode=$?
ssh $remote << RM
if [[ -f $tempScript ]]; then
rm $tmpScript
fi
RM
exit $errorCode
It was there that I was redirecting stdin, not ssh. I should have mentioned this when I formulated my question. I read through that script over and over again, but I guess I just overlooked that one line. Removing that line totally fixed my problem.
Just to clarify, changing my script to the following totally fixed my problem.
#!/bin/bash
tempScript="/tmp/myScript"
remote=user#host
commands="$#"
cat <(echo "$commands") | ssh $remote "cat > $tempScript && chmod +x $tempScript" &&
ssh -t $remote $tempScript
errorCode=$?
ssh $remote << RM
if [[ -f $tempScript ]]; then
rm $tmpScript
fi
RM
exit $errorCode
Once I changed my wrapper script, my test script described in the question worked! I was able to print "hello" to the screen, vim appeared and I was able to use it like normal, and then once I quit vim "goodbye" was printed and the ssh client closed.
The commenters to the question were pointing me in the right direction the whole time. I'm sorry I only told part of my story.
I've searched for solutions to this problem several times in the past, however never finding a fully satisfactory one. Piping into ssh looses your interactivity. Two connects (scp/ssh) is slower, and your temporary file might be left lying around. And the whole script on the command line often ends up in escaping hell.
Recently I encountered that the command line buffer size is usually quite large (getconf ARG_MAX > 2MB where I looked). And this got me thinking about how I could use this and mitigate the escaping issue.
The result is:
ssh -t <host> /bin/bash "<(echo "$(cat my_script | base64 | tr -d "\n")" | base64 --decode)" <arg1> ...
or using a here document and cat:
ssh -t <host> /bin/bash $'<(cat<<_ | base64 --decode\n'$(cat my_script | base64)$'\n_\n)' <arg1> ...
I've expanded on this idea to produce a fully working BASH example script sshx that can run arbitrary scripts (not just BASH), where arguments can be local input files too, over ssh. See here.

Resources