Inline unix command as filename [duplicate] - bash

This question already has answers here:
Why does my Bash code fail when I run it with 'sh'?
(2 answers)
Closed 4 years ago.
I have the following bash script test.sh (with execution permissions):
#!/bin/sh
CAT_BIN="cat"
"$CAT_BIN" <(tail -n +2 test.sh)
It gives me that error when I run it:
$ ./test.sh
./test.sh: line 4: syntax error near unexpected token `('
./test.sh: line 4: `"$CAT_BIN" <(tail -n +2 test.sh)'
However, when I source the following commands it executes alright.
$ CAT_BIN="cat"
$ "$CAT_BIN" <(tail -n +2 test.sh)
How can this work in a script? (Use <(tail -n +2 test.sh) inline as a filename argument)

The <(tail -n +2 test.sh) construct is a bash feature, so you need to run your script in the bash shell,
Replace your top line
#!/bin/sh
with
#!/bin/bash
(Or the proper path to the bash executable if it is not /bin/bash on your system)
Note, even if /bin/sh is e.g. a symlink to bash, it will start bash in posix compatibility mode when you run it as /bin/sh , and many bash specific features will not be available)

Related

Diffrence between bash script.sh and ./script.sh [duplicate]

This question already has answers here:
History command works in a terminal, but doesn't when written as a bash script
(3 answers)
Closed 2 years ago.
Suppose we have env.sh file that contains:
echo $(history | tail -n2 | head -n1) | sed 's/[0-9]* //' #looking for the last typed command
when executing this script with bash env.sh, the output will be empty:
but when we execute the script with ./env.sh, we get the last typed command:
I just want to know the diffrence between them
Notice that if we add #!/bin/bash at the beginning of the script, the ./env.sh will no longer output anything.
History is disabled by BASH in non-interactive shells by-default. If you want to enable it however, you can do so like this:
#!/bin/bash
echo $HISTFILE # will be empty in non-iteractive shell
HISTFILE=~/.bash_history # set it again
set -o history
# the command will work now
history
The reason this is done is to avoid cluttering the history by any commands being run by any shell scripts.
Adding hashbang (meaning the file is to be interpreted as a script by the program specified in your hashbang) to your script when being run via ./env.sh invokes your script using the binary /bin/bash i.e. run via bash, thus again printing no history.

Read command shows error as illegal option [duplicate]

This question already has answers here:
read: Illegal option -d
(2 answers)
Closed 5 years ago.
The following is my code
Read file
Count=0
While read -n1 c
Do
Case $c in
.
.
.
.
Esac
Done < $file
Echo"$count"
When I run this code, it shows the error as
read: Illegal option -n
I'm just started learning shell programming.So please help me fix this code
-n is not an option for read in standard Unix sh and (some of) its variants.
read -n runs well on bash, zsh and ksh93, so you may want to select one of them instead of sh or dash (Debian sh), probably by adding a shebang line:
#! /bin/bash
Or run explicitly with bash:
bash foo.sh

diff command not working inside bash shell script

I am trying to run
diff <(tar -tvf HIVE_CLIENT.tar.gz | sort) <(tar -tvf YARN_CLIENT.tar.gz | sort)
putting this command inside script, when I execute script it shows error
syntax error near unexpected token `(' "
But when I do not put inside script rather than run from shell directly it works.
Probably your script is run with /bin/sh and not with /bin/bash, but command substitution is a bash feature and not implemented in sh. So I suppose you are using bash as your shell which is why it is working from the command line.
Try adding this prefix to your script, and remove existing shebangs (like #!/bin/sh or similar):
#!/bin/bash
You should try following two actions:
Use #!/bin/bash as your shebang (First line of your script)
This may be needed based on your bash, use only if opetion 1 does not help. Use following commands to flip between posix mode which is needed for process substitution:
set +o posix
diff <(tar -tvf HIVE_CLIENT.tar.gz | sort) <(tar -tvf YARN_CLIENT.tar.gz | sort)
set -o posix
Example:
wc -l <(ls -lrt)
sh: syntax error near unexpected token `('
set +o posix
wc -l <(ls -lrt)
114 /dev/fd/00
set -o posix
wc -l <(ls -lrt)
sh: syntax error near unexpected token `('

Bash functions inside process substitution

Getting an error trying to call a function inside a process substitution.
Is there any way to do this?
#!/bin/bash
function testfunc
{
echo "bork"
}
diff <(testfunc) <(echo "bork")
The error is:
bork.sh: line 7: syntax error near unexpected token `('
bork.sh: line 7: `diff <(testfunc) <(echo "bork")'
--Update--
Problem was calling sh bork.sh, instead of bash ./bork.sh . Moral of the story make sure which shell you are executing with.
There's no problem here:
$ chmod +x test.sh
$ ./test.sh
Clear diff. No problem!
$ bash -x ./test.sh
+ diff /dev/fd/63 /dev/fd/62
++ testfunc
++ echo bork
++ echo bork
Proof that it worked
Troubleshooting:
Maybe you
run in a restricted shell
you don't have /dev/fd available/mounted correctly (due to somekind of secure chroot jail?)
The problem is probably that you're running the command with sh instead of bash.
$ cat > xx.sh
#!/bin/bash
function testfunc
{
echo "bork"
}
diff <(testfunc) <(echo "bork")
$ sh xx.sh
xx.sh: line 7: syntax error near unexpected token `('
xx.sh: line 7: `diff <(testfunc) <(echo "bork")'
$ bash xx.sh
$
The process substitution is not portable to the shell in /bin/sh. See the Bash manual on POSIX mode and bullet 28:
Process substitution is not available.
Tested on Mac OS X 10.10.5 (Yosemite).

bash for loop work in command line, but failed in script

When a run a for statement in debian bash command line, it works fine.
But when I run it in a sh script or run it with bash command, it's keeping report "error near unexpected token `do'"
Where is the difference?
[leon#www] ~/tmp $ for i in {1..10}; do echo $i; done
1
2
3
4
5
6
7
8
9
10
[leon#www] ~/tmp $ bash for i in {1..10}; do echo $i; done
-bash: syntax error near unexpected token `do'
BTW, all works fine in centos enviorment.
Use the -c option so that bash reads the commands from the string you pass in. Also, use single quotes around the command.
bash -c 'for i in {1..10}; do echo $i; done'
your bash command line ends with the first ;
so it gets executed separately as:
bash for i in {1..10};
do echo $i;
done
and man bash says command argument should be a file to load: bash [options] [file]
You can wrap all your script inside inverted commas or in a file. Because here, you're doing bash for i in {1..10} then do echo $i and so on. You should use -c option if you don't put it in a file.

Resources