Bash shell argument passing...? - linux

You can use a semicolon in bash shell to specify multiple commands.
Sometimes, one of those commands pops a question, requiring user input. (typically 'y' / 'n', or whatever really)
If I know what I want to answer in advance, is there a way to parse it to the commands somehow, like an argument, or some weird magical pipe stuff?

You don't need any "weird magical pipe stuff", just a pipe.
./foo ; echo "y" | ./bar ; ./baz
Or magical herestring syntax if you prefer:
./foo ; ./bar <<<"y" ; ./baz

You can use the yes command to put a lot of 'y' 's to a pipe.
For example, if you want to remove all your text files, you can use
yes | rm -r *.txt
causing every question asked by rm being answered with a y.
If you want another default answer, you can give it as an argument to yes:
yes n | rm -r *.txt
This will output a 'n'.
For more information, see http://en.wikipedia.org/wiki/Yes_(Unix)

For the simple "yes" answer there is a command yes, available on most Unix and Linux platforms:
$ yes | /bin/rm -i *
For an advanced protocol you may want to check the famous Expect, also widely available. It needs basic knowledge of Tcl.

First, it's not bash popping these questions. It is the particular program called (for instance, cp -i asks before overwriting files). Frequently those commands also have switches to answer the questions, like -y for fsck, or how -f overrides -i in rm. Many programs could be answered through a pipe, which is why we have the command "yes", but some go to extra lengths to ensure they cannot; for instance ssh when asking for passwords. Also, there's nothing magical about pipes. If the program only sometimes asks a question, and it matters what question, there are tools designed for that such as "expect".
In a typical shell script, when you do know exactly what you want to feed in and the program accepts input on stdin, you could handle it using a plain pipe:
echo -e '2+2\n5*3' | bc
If it's a longer piece then a here document might be helpful:
bc <<EOF
2+2
3*5
EOF

Sometimes a command provides an option to set default answer to a question. One notable example is apt-get - a package manager for Debian/Ubuntu/Mint. It provides and options -y, --yes, --assume-yes to be used in non-interactive scripts.

Related

How make linux output "async" output like, htop or top

How can I make a output like htop?
That is to say that the information is continually reinforced.
I had thought of something like this but I don't think it's completely right and I'm sure there are better ways to do it.
while true ; do
ls
sleep 3
clear
done
I would like to do it with bash but I am open to other proposals.
You can use watch utility for such a task:
$ watch -n 10 script.sh
the above command will execute the script.sh every 10 seconds you can change it through n option.
or for your command you can do it like this:
$ watch -n 3 ls
htop uses ncurses (https://www.gnu.org/software/ncurses/) which is a C library developed for making terminal interfaces.
If you'd like to stick with plain old bash, you could try echoing some output, then echoing backspace \b characters and spaces to overwrite it, followed by echoing new output again. You can also make use of system tools like tput to get terminal dimensions and things of that nature. I would suggest not going the bash route however.

Checking whether a program exists

In the middle of my perl script I want to execute a bash command. The script takes a long time, so at the beginning of the script I want to see if the command exists. This answer says to just try and run it and this other answer suggests some bash commands to test if the program exists.
Is the latter option the best solution? Are there any better ways to do this check in perl?
My best guess is that you want to check for existence of an executable file that you want to run using system or qx//
But if you want your command line to behave the same way as the shell, then you can probably use File::Which
What if we assume that we don't know the command's location?
This means that syck's answer won't work, and zdim's answer is incomplete.
Try this function in perl:
sub check_exists_command {
my $check = `sh -c 'command -v $_[0]'`;
return $check;
}
# two examples
check_exists_command 'pgrep' or die "$0 requires pgrep";
check_exists_command 'readlink' or die "$0 requires readlink";
I just tested it, because I just wrote it.
With perl, you can test files for existence, readability, executability etc., take a look here.
Therefore just use
executeBashStuff() if -x $filename;
or stat it:
stat($filename);
executeBashStuff() if -x _;
To me a better check is to run the program at the beginning of the script (with -V say).
I'd use the same invocation as you use to run the job later (via shell or not, via execvp). Once at it, make sure to see whether it threw errors. This is also discussed in your link but I would in fact get the output back (not send it away) and check that. This is the surest way to see whether the thing actually runs out of your program and whether it is what you expect it to be.
Checking for the executable with -x (if you know the path) is useful, too, but it only tells you that a file with a given name is there and that it is executable.
The system's which seems to be beset with critism for its possible (mis)behavior, it may or may not be a shell-builtin (which complicates how exactly to use it), is an external utility, and its exact behavior is system dependent. The module File::Which pointed out in Borodin's answer would be better -- if it is indeed better than which. (What it may well be, I just don't know.)
Note. I am not sure what "bash command" means: a bash shell built-in, or the fact that you use bash when on terminal? Perl's qx and system use the sh shell, not bash (if they invoke the shell, which depends on how you use them). While sh is mostly a link, and often to bash, it may not be and there are differences, and you cannot rely on your shell configuration.
Can also actually run a shell, qx(/path/bash -c 'cmd args'), if you must. Mind the quotes. You may need to play with it to find the exact syntax on your system. See this page and links.

predefined input in a nohup shell script [duplicate]

I have a script that calls an application that requires user input, e.g. run app that requires user to type in 'Y' or 'N'.
How can I get the shell script not to ask the user for the input but rather use the value from a predefined variable in the script?
In my case there will be two questions that require input.
You can pipe in whatever text you'd like on stdin and it will be just the same as having the user type it themselves. For example to simulating typing "Y" just use:
echo "Y" | myapp
or using a shell variable:
echo $ANSWER | myapp
There is also a unix command called "yes" that outputs a continuous stream of "y" for apps that ask lots of questions that you just want to answer in the affirmative.
If the app reads from stdin (as opposed to from /dev/tty, as e.g. the passwd program does), then multiline input is the perfect candidate for a here-document.
#!/bin/sh
the_app [app options here] <<EOF
Yes
No
Maybe
Do it with $SHELL
Quit
EOF
As you can see, here-documents even allow parameter substitution. If you don't want this, use <<'EOF'.
the expect command for more complicated situations, you system should have it. Haven't used it much myself, but I suspect its what you're looking for.
$ man expect
http://oreilly.com/catalog/expect/chapter/ch03.html
I prefer this way: If You want multiple inputs... you put in multiple echo statements as so:
{ echo Y; Y; } | sh install.sh >> install.out
In the example above... I am feeding two inputs into the install.sh script. Then... at the end, I am piping the script output to a log file to be archived and viewed for later.

How to use grep to find data conveniently and quickly

I am asking for general opinions on how to find files quickly.
One typical scenario is that I often need to grep some names from a PeopleNameFile.txt from Dir1. When I'm in a different directory, I am forced to grep the file with a long directory path. It would be nice to just do GREP "Warren Buffett" PeopleNameFile.txt.
BTW, I'm using Cygwin but I welcome any suggestions.
You can easily write a simple bash function in your ~/.bashrc:
function grnm() {
grep "$#" /path/to/peoplenamefile.txt
}
Then later on, at command line you can type:
$ grnm "Warren Buffet"
the nice thing is that you can actually include other grep parameters if you like as in:
$ grnm -i "warren buffet"
(The $ characters represent your shell prompt, not part of the command you type.)
When you edit the .bashrc file FOR THE FIRST TIME you may have to source it in your existing open cygwin windows:
$ source ~/.bashrc
But if you open a new window you should not have to do that.
Good luck, have fun
You can create script my_grep.sh and add it somewhere to you path, with content like this:
#!/bin/bash
grep $1 path/to/Dir1/PeopleNameFile.txt
than you just type
my_grep.sh "Warren Buffett"
also you can use alias and bash's function,
but this require to edit "~/.bashrc".
Simplest option would be to setup an alias which would grep for that file using the absolute path. Not sure whether cygwin allows aliases though.
Probably the most common way to do these kind of things is to use environment variables
e.g.
PNF='/very/long/path/PeopleNameFile.txt'
grep "Warren Buffett" $PNF

what does '-' stand for in bash?

What exactly are the uses of '-' in bash? I know they can be used for
cd - # to take you to the old 'present working directory'
some stream generating command | vim - # somehow vim gets the text.
My question is what exactly is - in bash? In what other contexts can I use it?
Regards
Arun
That depends on the application.
cd -
returns to the last directory you were in.
Often - stands for stdin or stdout. For example:
xmllint -
does not check an XML file but checks the XML on stdin. Sample:
xmllint - <<EOF
<root/>
EOF
The same is true for cat:
cat -
reads from stdin. A last sample where - stands for stdout:
wget -O- http://google.com
will receive google.com by HTTP and send it on stdout.
By the way: That has nothing to do with your shell (e.g. bash). It's only semantics of the called application.
- in bash has no meaning as a standalone argument (I would not go as far as to say it it does not have a meaning in shell at all - it's for example used in expansion, e.g. ls [0-9]* lists all files starting with a digit).
As far as being a standalone parameter value, bash will do absolutely nothing special with it and pass to a command as-is.
What the command does with it is up to each individual program - can be pretty much anything.
There's a commonly used convention that - argument indicates to a program that the input needs to be read from STDIN instead of a file. Again, this is merely how many programs are coded and technically has nothing to do with bash.
From tldp:
This can be done for instance using a hyphen (-) to indicate that a program should read from a pipe
This explains how your vim example gets its data.
There is no universal rule here.
According to the context it changes
It is pretty much useful when you have something to do repeatedly in two directories. Refer #4 here: http://www.thegeekstuff.com/2008/10/6-awesome-linux-cd-command-hacks-productivity-tip3-for-geeks/
In many places it means STDIN.

Resources