why sh softlink to bash doesn't work? [duplicate] - linux

I have a shell script which uses process substitution
The script is:
#!/bin/bash
while read line
do
echo "$line"
done < <( grep "^abcd$" file.txt )
When I run the script using sh file.sh I get the following output
$sh file.sh
file.sh: line 5: syntax error near unexpected token `<'
file.sh: line 5: `done < <( grep "^abcd$" file.txt )'
When I run the script using bash file.sh, the script works.
Interestingly, sh is a soft-link mapped to /bin/bash.
$ which bash
/bin/bash
$ which sh
/usr/bin/sh
$ ls -l /usr/bin/sh
lrwxrwxrwx 1 root root 9 Jul 23 2012 /usr/bin/sh -> /bin/bash
$ ls -l /bin/bash
-rwxr-xr-x 1 root root 648016 Jul 12 2012 /bin/bash
I tested to make sure symbolic links are being followed in my shell using the following:
$ ./a.out
hello world
$ ln -s a.out a.link
$ ./a.link
hello world
$ ls -l a.out
-rwx--x--x 1 xxxx xxxx 16614 Dec 27 19:53 a.out
$ ls -l a.link
lrwxrwxrwx 1 xxxx xxxx 5 May 14 14:12 a.link -> a.out
I am unable to understand why sh file.sh does not execute as /bin/bash file.sh since sh is a symbolic link to /bin/bash.
Any insights will be much appreciated. Thanks.

When invoked as sh, bash enters posix
mode after the startup files are read. Process substitution is not recognized in posix mode. According to posix, <(foo) should direct input from the file named (foo). (Well, that is, according to my reading of the standard. The grammar is ambiguous in many places.)
EDIT: From the bash manual:
The following list is what’s changed when ‘POSIX mode’ is in effect:
...
Process substitution is not available.

Related

Difference in executing shell script by 'sh' and 'source' (and '.') [duplicate]

This question already has answers here:
Echo newline in Bash prints literal \n
(22 answers)
Difference between sh and Bash
(11 answers)
Closed 2 years ago.
I have a tiny question.
When I execute my shell file by 'sh', it works differently.
(it printed '-e')
Google says "Check your first line(#!/bin/bash) and 'env | grep sh'"
But there no do difference in my eyes...
Would you tell me why it is?
+++
I tried changing '#!/bin/bash' → '#!/bin/dash', but noting changed.
Thanks for reading..
[my first code(first.sh)] -bash
#!/bin/bash
echo -e "hi"
[run script and result]
# . first.sh
Hi
# source first.sh
Hi
# sh first.sh
-e hi
[my second code(second.sh)] -dash
#!/bin/dash
echo -e "hi"
[run script and result]
nothing change...
[OS]
ubuntu 18.04
[environment]
# env | grep sh
SHELL=/bin/bash
# ll /bin | grep sh
-rwxr-xr-x 1 root root 1113504 6월 6 2019 bash*
-rwxr-xr-x 1 root root 121432 1월 25 2018 dash*
lrwxrwxrwx 1 root root 4 6월 6 2019 rbash -> bash*
lrwxrwxrwx 1 root root 4 7월 18 2019 sh -> dash*
lrwxrwxrwx 1 root root 4 7월 18 2019 sh.distrib -> dash*
that is because the sh shell interpreter does not recognize -e as a flag and prints it as a regular string.
source and . use your SHELL env, which is bash, whom recognizes the -e flag and does not treat it as a string.

How do I use variable substitution in a remote ssh command when the variable value has spaces in it?

I've got the following test script:
#!/bin/bash
ssh -o StrictHostKeyChecking=no root#192.168.1.10 'ls -l "aaa bbb.txt"'
domain="aaa bbb.txt"
ssh -o StrictHostKeyChecking=no root#192.168.1.10 \'ls -l "${domain}"\'
The first command without the $domain variable works fine. Returns:
-rw-rw-rw- 1 root root 7 Nov 21 22:49 aaa bbb.txt
What I can't figure out is the second command. Running it returns the following from the remote server: bash: ls -l aaa bbb.txt: command not found
If I leave off the escaped backticks (ssh -o StrictHostKeyChecking=no root#192.168.1.10 ls -l "${domain}") I get the following error:
ls: cannot access 'aaa': No such file or directory
ls: cannot access 'bbb.txt': No such file or directory
How can I use variable substitution with spaces in the variable value in a remote ssh command?
Thanks.

When I use scp command through expect, asterisk can not recognized

Hello I have a one problem in linux shell
I write a scp script using expect and the script is like this.
#!/bin/sh
expect -c "spawn scp /tmp/data/*2017-06-14*.log2 id#localhost:~/"\
-c "expect -re \"password\" "/
-c "sleep 1" \
-c "send \"password\r\""\
-c "interact"
and result of execution shows error message.
/tmp/data/*2017-06-14*.log2 : No such file or directory
But When not use expect, scp execution is success
[user#localhost]# scp /tmp/data/*2017-06-14*.log2 id#localhost:~/"\
How can i solve this problem?
Expect does not understand shell's syntax. You can:
spawn sh -c "scp /tmp/data/*2017-06-14*.log2 id#localhost:~/"
or
spawn sh -c {scp /tmp/data/*2017-06-14*.log2 id#localhost:~/}
komar's answer using glob would not always work. See following example:
bash-4.4# expect
expect1.1> system pwd
/root/tmp/tcl
expect1.2> system ls -l
total 0
-rw-r--r-- 1 root root 0 Jun 16 10:55 a b
-rw-r--r-- 1 root root 0 Jun 16 10:55 c d
expect1.3> spawn ls -l [glob *]; expect eof
spawn ls -l {a b} {c d}
ls: cannot access {a b} {c d}: No such file or directory
expect1.4> spawn sh -c "ls -l *"; expect eof
spawn sh -c ls -l *
-rw-r--r-- 1 root root 0 Jun 16 10:55 a b
-rw-r--r-- 1 root root 0 Jun 16 10:55 c d
expect1.5>
You need globbing in expect/tcl style:
expect -c "spawn scp [glob /tmp/data/*2017-06-14*.log2] id#localhost:~/"

Bash: Running one command after another using string variable

I understand that running one command after another is done in bash using the following command
command1 && command2
or
command1; command2
or even
command1 & command2
I also understand that a command stored in a bash variable can be run by simply firing the variable as:
TestCommand="ls"
$TestCommand
Doing the above will list all the files in the directory and I have tested that it does.
But doing the same with multiple commands generates an error. Sample below:
TestCommand="ls && ls -l"
$TestCommand
ls: cannot access &&: No such file or directory
ls: cannot access ls: No such file or directory
My question is why is this happening and is there any workaround?
And before you bash me for doing something so stupid. The preceding is just to present the problem. I have a list of files in my directory and I am using sed to convert the list into a single executable string. Storing that string in a bash variable, I am trying to run it but failing.
When you put two command in a single string variable, it is executed as single command. so when you are using "$TestCommand" to execute two "ls" commands, it is executing only one(first) "ls" command. it considers && and ls(second) as argument of first ls command.
As your current working directory is not having any files named && and ls it is returning error :
ls: cannot access &&: No such file or directory
ls: cannot access ls: No such file or directory
So, basically your commands behaves like this
ls file1 file2 -l
and it will give you output like this if file1 and file2 exists:
HuntM#~/scripts$ ls file1 file2 -l
-rw-r--r-- 1 girishp staff 0 Dec 8 12:44 file1
-rw-r--r-- 1 girishp staff 0 Dec 8 12:44 file2
Now your solution:
You can create function OR one more script to execute 2 commands as below:
caller.sh
#!/bin/bash
myLs=`./myls.sh`
echo "$myLs"
myls.sh
#!/bin/bash
ls && ls -l

Why does "/usr/bin/env bash -x" only work in command line?

I am playing with a docker CentOS image, and find executing "/usr/bin/env bash -x" command is OK in terminal:
bash-4.1# /usr/bin/env bash -x
bash-4.1# exit
+ exit
exit
But after writing this command into a script and execute it, it doesn't work, and prompts "No such file or directory":
bash-4.1# ls -lt a.sh
-rwxr-xr-x. 1 root root 23 May 20 04:27 a.sh
bash-4.1# cat a.sh
#!/usr/bin/env bash -x
bash-4.1# ./a.sh
/usr/bin/env: bash -x: No such file or directory
Is there any difference between two methods?
The short answer is that you only get one parameter to the interpreter which is specified via the "#!" mechanism. That became "bash -x".
Usually the limitation is more apparent, e.g., using
#!/bin/bash -x -i
would pass "-x -i" as the parameter, and get unexpected results.
Sven Mascheck comments on this in his page on the topic:
most systems deliver all arguments as a single string
The shebang line should have at most one argument.
When you give more arguments, they will not be split. You can compare this with the commandline command
bash-4.1# /usr/bin/env "bash -x"

Resources