From within a shell script I want to access input given from other command - bash

I am messing around with shell scripts and I am trying to get my script to take input from another command, like say ls. It is called like this:
ls | ./example.sh
I try to access the input from within example.sh
#!/bin/bash
echo $1
but it echoes back nothing. Is there another way to reference parameters given to bash by other commands, because it works if I type in:
./example.sh poo

Parameters and input aren't the same thing:
$ ls
example.sh foo
$
$ cat example.sh
for param; do
printf 'argument 1: "%s"\n' "$param"
done
while IFS= read -t 1 -r input; do
printf 'input line: "%s"\n' "$input"
done
$
$ ls | ./example.sh
input line: "example.sh"
input line: "foo"
$
$ ls | ./example.sh bar
argument 1: "bar"
input line: "example.sh"
input line: "foo"
$
$ ./example.sh $(ls)
argument 1: "example.sh"
argument 1: "foo"
Parameters are the arguments passed to the script to start it running, input is what the script reads while it's running.

You can use xargs to do that.
ls | xargs ./example.sh
Resource
https://ss64.com/bash/xargs.html
https://www.cyberciti.biz/faq/linux-unix-bsd-xargs-construct-argument-lists-utility/
Or read man page for it

Related

Is there a way to print interpolated shell commands while preserving redirections?

Suppose I have the following shell program.
#!/bin/sh
FOO="foo"
echo $FOO | cat
I want to generate another shell program that does the same thing as this one, except that all shell variables have been substituted. For example,
#!/bin/sh
echo "foo" | cat
I know that I can get close if I run the above program using #!/bin/sh -x, but that output does not preserve redirections. Instead, I get
+ FOO=foo
+ echo foo
+ cat
foo
Any ideas?
The following shell:
$ cat eval.sh
echo "#!/bin/sh"
FOO="foo"
echo "echo $FOO | cat"
will write a shell:
$ sh eval.sh
#!/bin/sh
echo foo | cat
which does what you need.

Testing whether stdin is a file vs. a pipe vs. a tty

I know for bash and zsh, one can use e.g. [ -t 1 ] to determine if STDIN is an interactive tty session.
However, there doesn't seem to be a way to test whether stdin is being redirected from a file, versus being piped in from a command:
foo < ./file
bar | foo
Is there any way to detect the difference between these two? Separately, is there any way to get the path of the file being redirected from (outside of /proc/self, which is unavailable on macOS)?
You can check if /dev/stdin is a regular file or a pipe:
$ cat tmp.sh
#!/bin/bash
if [ -f /dev/stdin ]; then
echo "file"
elif [ -p /dev/stdin ]; then
echo "pipe"
fi
$ bash tmp.sh < foo.txt
file
$ echo foo | bash tmp.sh
pipe
This relies on /dev/stdin being in your file system, though.
You can also use the stat command, which will return information about standard input given no file name argument. As you mentioned you are using macOS, you can use the %HT format:
$ stat -f %HT
Character Device
$ stat -f %HT < foo.txt
Regular File
$ echo foo | stat -f %HT
Fifo File

How to pass argument in bash pipe from terminal

i have a bash script show below in a file called test.sh
#!/usr/bin/env bash
echo $1
echo "execution done"
when i execute this script using
Case-1
./test.sh "started"
started
execution done
showing properly
Case-2
If i execute with
bash test.sh "started"
i'm getting the out put as
started
execution done
But i would like to execute this using a cat or wget command with arguments
For example like.
Q1
cat test.sh |bash
Or using a command
Q2
wget -qO - "url contain bash" |bash
So in Q1 and Q2 how do i pass argument
Something simlar to this shown in this github
https://github.com/creationix/nvm
Please refer installation script
$ bash <(curl -Ls url_contains_bash_script) arg1 arg2
Explanation:
$ echo -e 'echo "$1"\necho "done"' >test.sh
$ cat test.sh
echo "$1"
echo "done"
$ bash <(cat test.sh) "hello"
hello
done
$ bash <(echo -e 'echo "$1"\necho "done"') "hello"
hello
done
You don't need to pipe to bash; bash runs as standard in your terminal.
If I have a script and I have to use cat, this is what I'll do:
cat script.sh > file.sh; chmod 755 file.sh; ./file.sh arg1 arg2 arg3
script.sh is the source script. You can replace that call with anything you want.
This has security implications though; just running an arbitrary code in your shell - especially with wget where the code comes from a remote location.

Bash: How to perform redirection coming from variable expansion

I am trying to run a command with a variable which holds another command that suppresses warning messages of the jar. However, it is not working as expected and I can't figure out what I am doing wrong.
TEST=${TEST:-2> /dev/null}
java -jar ~/bin/aw.jar ${Test}
Redirection is performed only if it is unquoted and present in the command line literally rather than originating from any kind of expansion:
$ ls
$ echo hello >out
$ ls
out
$ cat out
hello
$ rm *
$ echo hello '>out'
hello >out
$ ls
$ x='>out'
$ echo hello $x
hello >out
$ ls
In order to interpret redirection operator coming from a quoted string or an expansion you must execute the command through eval (note, however, that this may result in undesired expansions in other parts of your command):
$ ls
$ x='>out'
$ eval echo hello $x
$ ls
out
$ cat out
hello

How do I use the file redirected to the standard input of a bash script?

How do I use the file redirected to the standard input of a bash script?
$ script.sh < file_to_use_in_script
what do I have to put in my script, so that I can write the filename in a variable from this input, without knowing the pathname beforehand.
FILENAME=$file_to_use_in_script
You can use the filename /dev/stdin. Make sure to only read it once.
$ cat myscript
#!/bin/bash
file=${1:-/dev/stdin}
echo "Reading from $file"
nl "$file"
$ cat myfile
hello world
$ ./myscript myfile
Reading from myfile
1 hello world
$ ./myscript < myfile
Reading from /dev/stdin
1 hello world
$ echo "something" | ./myscript
Reading from /dev/stdin
1 something
i would suggest to pass the filename as a an argument, you obviously know it anyway
echo "name $1"
while read line
do
echo $line
done
and then:
./test.sh foo/bar.txt < foo/bar.txt
gives
name foo/bar.txt
1
2
3
if foo/bar.txt contains
1
2
3

Resources