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

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"

Related

Bash shell: command not found

I am using the shell module to execute the following command
tasks:
- name: Command
shell: "sshpass -p 123 ssh -o 'StrictHostKeyChecking no' root#10.67.13.50 shell << EOF \n whoami\nEOF | cat"
I am getting the following error
"stderr_lines": [
"/bin/sh: line 2: warning: here-document at line 0 delimited by end-of-file (wanted `EOF')",
"Warning: Permanently added '10.67.13.50' (ECDSA) to the list of known hosts.",
"bash: shell: command not found"
]
What is wrong with my command?
tl;dr you can either a) replace shell with sh or bash, or b) replace shell with whoami and drop the heredoc.
Let's decompose the shell command:
sshpass -p 123 ssh -o 'StrictHostKeyChecking no' root#10.67.13.50 shell << EOF \n whoami\nEOF | cat
There are several processes happening here.
A sh pipeline with two subprocesses:
sshpass which then runs as a subprocess…
ssh which connects to 10.67.13.50 and runs…
shell with \n whoami\n as its standard input
… and cat, which takes the output from the sshpass process hierarchy
There are a couple potential bugs:
You can safely remove cat from the pipeline.
As #KamilCuk mentioned, cat reads from its input and writes it out. It isn't doing anything here; it's neither useful nor harmless.
shell is not a command on the remote server (10.67.13.50). If you want to run a shell, typically sh or bash is used.
Moreover, you can replace the entire shell … EOF sequence with whoami.
The << EOF \n whoami \nEOF is a heredoc to tell the shell on the remote server what commands to execute. However, there is only one command executed.
In summary, the shell: line could be rewritten as:
sshpass -p 123 ssh -o 'StrictHostKeyChecking no' root#10.67.13.50 whoami
… an odd command, since we know the remote user root.

What kind of command is "sudo", "su", or "torify"

I know what they do. I was just wondering what kind of command are they. How can you make one using shell scripting.
For example, command like:
ignoreError ls /Home/
ignoreError mkdir /Home/
ignoreError cat
ignoreError randomcommand
Hope you get the idea
The way to do it in a shell script is with the "$#" construct.
"$#" expands to a quoted list of all of the arguments you passed to your shell script. $1 would be the command you want your shell script to run, and $2 $3 etc are the arguments to that command.
The only example I have is from cygwin. Cygwin does not have sudo, but I have this script that emulates it:
#!/usr/bin/bash
cygstart --action=runas "$#"
So when I run a command like
$ sudo ls -l
my sudo script does whatever it needs to do (cygstart --action=runas) and calls the ls command with the -l argument.
Try this script:
#!/bin/sh
"$#"
Call it, for example, run, make it runnable chmod u+x run, and try it:
$ run ls -l #or ./run ls -l
...
output of ls
...
The idea is that the script takes the parameters specified on the command line and use them as a (sub)command... Modify the script this way:
#!/bin/sh
echo "Trying to run $*"
"$#"
and you will see.

Option -l of exec shell command

Could you please clarify on the use of -l option of exec shell command. I didn't notice any difference when I ran exec ls | cat and exec -l ls | cat.
The -l option of exec adds a - at the beginning of the name of your command. For example:
exec -l diff | head
-diff: missing operand after '-diff'
-diff: Try '-diff --help' for more information.
Note the - everywhere before diff.
The point of all this? If you have a - before a command to start a shell it will act as a login shell. From man bash:
A login shell is one whose first character of argument zero is a -, or one started with the --login option.
Now, man exec states that:
If the -l option is supplied, the shell places a dash at the beginning of the zeroth argument passed to command. This is
what login(1) does.
So exec -l bash will run bash as a login shell. To test this, we can use the fact that a login bash executes the file ~/.bash_profile, so:
$ cat ~/.bash_profile
#!/bin/sh
printf "I am a login shell!\n"
If I start a login bash, the command printf "I am a login shell!\n" will be executed. Now to test with exec:
$ exec bash
$
Nothing is displayed, we are on a non-login shell.
$ exec -l bash
I am a login shell!
$
Here we have a login shell.

Using linux script command

The script command executes and records logs.
( http://www.computerhope.com/unix/uscript.htm )
( http://linuxers.org/article/script-command-line-tool-recordsave-your-terminal-activity )
I use script command for saving commands and those output.
Whenever using 'script', I type commands like followings.
$ script result.log
Script started, file is result.log
$ date
$ ls -la.
$ exit
Sometimes I want to use those command with shell script.
So I run like following.
$ script -c test.sh result.log
But the result.log has only output, it doesn't contain command itself.
I want the result.log to include commands and output.
How can I do it?
Thanks
if you use sh -x to run your script it will print the commands or add
set -x to your script.
script -c "sh -x ./test.sh" reult.log
sample output:
+ date
Tue Dec 23 09:52:22 CET 2014
+ ls -la
set -o verbose
Execute this on terminal before executing your script or add this at the beginning of the script.
This will change the terminal configuration to echo all the commands before executing them.
This will add the command then followed by the output of that command.
you can also use :
set -x or set -v set -xv
-x option enables variable expansion and echo's all the option used with the command.
-v is similar to -o verbose this simply echo's the command name
-xv echo's both.

Error q : Command not found on Vim

I created a bash script :
#!/bin/bash
su root -c vim $1 -c ':%s/^M//g' -c 'wq'
My script has to remove all the ^M (carriage return on Windows) on my file, then save it.
When I execute my script it returns :
/sequenceFiles/Sequence1.seq: wq: command not found
Does someone know why ?
Thanks for your help.
The -c is seen by su, not vim, and the shell complains about the unknown command.
You need to pass the command as one argument to su:
su root -c "vim $1 -c ':%s/^M//g' -c 'wq'"
man su says:
`-c COMMAND'
`--command=COMMAND'
Pass COMMAND, a single command line to run, to the shell with a
`-c' option instead of starting an interactive shell.
Try
su root -c "vim $1 -c ':%s/^M//g' -c 'wq'"
While you can do it with vim, consider simpler:
perl -pi -e 's/\r\n/\n/' file

Resources