I am a beginner of bash. I encounter a problem like this:
$ "make -p"
when I type the above in bash command line, there is nothing to happen, no error, no result msg.
I have searched double quotes syntax of bash in many websites. All of these materials give similar interpretation as below:
https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
and give examples like:
echo "argument"
I do not find something like "echo argument". Moreover, I find a strange difference between bash command line and bash scripts.
If I type a non-existing command in command line:
$ "holy shit"
$ "look that"
there is nothing to happen. But if I type it in bash scripts:
#!/bin/bash
"holy shit"
"look that"
and execute this script, an error msg will be throw out:
$ ./myshell
./myshell: line 2: holy shit: command not found
./myshell: line 3: look that: command not found
Would someone can help give a detailed interpretation about the effect of double quotes when they enclosed the whole command?
Why there is no output in command-line?
Why it is different between command line and scripts?
If you enter a command foo, the shell searches the directories listed in your PATH variable until it finds a command of this name. If there is none, you get the error message command not found.
If you enter a command, which contains at least one slash - for example ./foo or foo/bar -, the shell does not search the PATH, but assumes that you have already entered the correct path to your command. If it does not exist, you get the error message No such file or directory.
In your case,
"cd home"
searches for a file with name cd home somewhere along your PATH, but there is no file of this name, and you get command not found. If you enter
"cd /home"
the shell bypasses PATH-search and assumes, that there exists a directory named cd (i.e. the 3 letters c,d,space) in your current directory, and below it a file named home, with x-bit set. There is no such file (and no such directory) on your system, and you get the error message No such file or directory.
If you are in the mood of experimenting around, you could try the following:
mydir="cd "
mkdir "$mydir"
echo "echo Hello Stranger" >"$mydir/home"
chmod +x "$mydir/home"
"cd /home"
This should print Hello Stranger. Pay attention that in the assignment to mydir, there must be a single space between the cd and the closing quote.
The double quotes mean it is a string. You can do something like:
echo "Hello everybody"
either at the command line or the shell. Sometimes when people put stuff in quotes. you are supposed to replace what is in quotes with your own variable (removing the quotes), and sometimes people put quotes around the whole command you are supposed to type to show the what exactly you should type. For your example of "make -p" just type it without the quotes and it should work in both the command line and as a script.
Related
I can't figure out the right syntax to run a shell command in a post-build step in Cmake on Linux. I can make a simple echo work, but when I want to e.g. iterate over all files and echo those, I'm getting an error.
The following works:
add_custom_command(TARGET ${MY_LIBRARY_NAME}
POST_BUILD
COMMAND echo Hello world!
USES_TERMINAL)
This correctly prints Hello world!.
But now I would like to iterate over all .obj files and print those. I thought I should do:
add_custom_command(TARGET ${MY_LIBRARY_NAME}
POST_BUILD
COMMAND for file in *.obj; do echo #file ; done
VERBATIM
USES_TERMINAL)
But that gives the following error:
/bin/sh: 1: Syntax error: end of file unexpected
I've tried all sorts of combinations with quotation marks or starting with sh, but none of that seems to work. How can I do this correctly?
add_custom_command (and all the other CMake functions that execute a COMMAND) don't run shell scripts, but only allow the execution of a single command. The USES_TERMINAL doesn't cause the command to be run in an actual terminal or allow the use of shell builtins like the for loop.
From the documentation:
To run a full script, use the configure_file() command or the file(GENERATE) command to create it, and then specify a COMMAND to launch it.
Or, alternatively, for very simple scripts you can do what #lojza suggested in the comment to your question and run the bash command with the actual script content as an argument.
add_custom_command(
TARGET ${MY_LIBRARY_NAME}
POST_BUILD
COMMAND bash -c [[for file in *.obj; do echo ${file}; done]]
VERBATIM
)
Note that I deliberately used a CMake raw string literal here so that ${file} is not expanded as a CMake variable. You could also use bash -c "for file in *obj; do echo $file; done" with a regular string literal, in which case $file also isn't expanded due to the lack of curly braces. Having copied and pasted bash code from other sources into CMake before I know how difficult it is to track down bugs caused by an unexpected expansions of CMake variables in such scripts, though, so I'd always recommend to use [[ and ]] unless you actually want to expand a CMake variable.
However, for your concrete example of doing something with all files which match a pattern there is an even simpler alternative: Use the find command instead of a bash loop:
add_custom_command(
TARGET ${MY_LIBRARY_NAME}
POST_BUILD
COMMAND find
-maxdepth 1
-name *.obj
-printf "%P\\n"
VERBATIM
)
Sometimes, proper scripting of the COMMAND could be performed using debugging.
Below the error message there is a point to the line which causes it. Something like
/bin/sh: 1: Syntax error: end of file unexpected
make[2]: *** [CMakeFiles/my_target.dir/build.make:57: CMakeFiles/my_target] Error 2
So, you can look into the line 57 of the file CMakeFiles/my_target.dir/build.make and find out the command which is actually placed into the Makefile:
CMakeFiles/my_target:
for file in "*.obj" do echo #file done
As you can see, CMake drops all semicolons (;): this is because this symbol is a separator for CMake.
Quoting semicolons doesn't help in VERBATIM mode:
The commmand
COMMAND for file in *.obj ";" do echo #file ";" done
is transformed
CMakeFiles/my_target:
for file in "*.obj" ";" do echo #file ";" done
But shell doesn't treat quoted semicolons (";") as commands separator!
Omitting VERBATIM gives better transformation:
CMakeFiles/my_target:
for file in *.obj ; do echo #file ; done
The next step is to properly refer to the file variable in the script (# is definitely a wrong way). A script should see either $file or ${file}, but both CMake and Make have a special way for process a dollar ($). (VERBATIM could automatically escape things for the Make, but we cannot use it because of semicolons.)
Resulted command could be either
COMMAND for file in *.obj ";" do echo $$file ";" done
or
COMMAND for file in "CMake*" ";" do echo $\${file} ";" done
As you can see, even VERBATIM doesn't handle all situations correctly.
I found the below snippet at the .sh file of my project to define some path :
PGMPATH=`pwd|sed -e "s#/survey1##" `
What does the above line means ?
Reference of PGMPATH is used as below :
LIBS="${LIBS}:${PGMPATH}/edmz-par-api_1.4.jar"
LIBS="${LIBS}:${PGMPATH}/commons-logging.jar"
If it is telling the path where the jar file is located , please explain how it works .
So first you should know that this is two commands - pwd and sed -e "s#/survey1##" - and these two commands are being run together in a pipeline. That is, the output of the first command is being sent to the second command as input.
That is, in general, what | means in unix shell scripts.
So then, what do each of these commands do? pwd stands for "print working directory" and prints the current directory (where you ran the script from, unless the script itself had any cd commands in it).
sed is a command that's really a whole separate programming language that people do many simple text-processing commands with. The simple sed program you have here - s#/survey1## - strips the string /survey1 out of its input, and prints the result.
So the end result is that the variable PGMPATH becomes the current directory with /survey1 stripped out of it.
In a sh script I came across, I found the lines
#\
MAKE_LINTIAN_HAPPY '
close to the beginning.
From the name of the identifier, it is clear why it was added. But my question is: Why is this legal sh code and what (if anything) does it do?
The reason I ask is that it renders GNU's source-highlight useless on this script since it will interpret all of the file after the tick as a string. If I know why it's legal, it might be possible to suggest an edit to the language definition file to fix this.
I tried to search the man pages for sh for clues with
$ man sh|grep "\W'\W"
but none of the matches seem to be of help (there are many matches though so I might have missed it if it's there).
I don't understand the #\ either; I don't know if this is unrelated to this question or not. (Vim will syntax-color the line following #\ as a comment, but a simple test shows that sh does execute the line following #\.)
Here's an extended excerpt of the beginning of the script:
#!/bin/sh
# [...]
#\
exec tclsh $0 -- "$#"
#\
MAKE_LINTIAN_HAPPY '
set PROG_VERSION "v1.27 17/06/2005"
The script you are looking at is in fact not a shell (sh, bash, dash, etc) script, but a tclsh script. When you start it, then, in fact, /bin/sh is first started. The very first command it executes is
exec tclsh $0 -- "$#"
meaning it fires up tclsh and passes the very script file to tclsh. Now tclsh starts to interpret the script. It also has '#' as the start of a line comment, but in contrast to sh, the line comment can be extended to the next line, if the end-of-line is escaped, hence #\.
So the MAKE_LINTIAN_HAPPY line is not a command for tclsh, it is just ignored. The first command executed by tclsh is set PROG_VERSION ....
I don't know lintian. This line may have exactly the purpose of letting lintian "misinterpret' the contents of the file as just text, because it would otherwise think it is an sh script and would yell loud about policy violations.
I need some help understanding following shell script line,
apphome = "`cd \`dirname $0\` && pwd && cd - >/dev/null`"
All I understand is, this is creating a variable called apphome.
This is not a valid shell code.
The shell don't allow spaces around =
For the rest, while this seems broken, it try to cd to the dir of the script itself, display the current dir & finally cd back to the latest cd place redirecting his standard output STDOUT to the /dev/null trash-bin (that's makes not any sense, cd display only on standard error STDERR when it fails, never on STDOUT)
If you want to do this in a proper a simple way :
apphome="$(dirname $0)"
That's all you need.
NOTE
The backquote
`
is used in the old-style command substitution, e.g.
foo=`command`
The
foo=$(command)
syntax is recommended instead. Backslash handling inside $() is less surprising, and $() is easier to nest. See http://mywiki.wooledge.org/BashFAQ/082
It seems to assign a command to the "apphome" variable. This command can be executed later.
dirname returns a directory portion of a file name. $0 is the name of the script this line contains (if I am not mistaken).
Now, executing dirname <name> will return a directory, and cd will use the value.
So, what it would do is execute three command in the row assuming that each one of them succeeds. The commands are:
cd `dirname [name of the script]`
pwd
cd -
First command will change directory to the directory containing your script; second will print current directory; third will take yo back to the original directory. Output of the third command will not be printed out.
In summary, it will print out a name of a directory containing the script that contains the line in question.
At least, this is how I understand it.
Every time I run a script using bash scriptname.sh from the command line in Debian, I get Command Not found and then the result of the script.
The script works but there is always a Command Not Found statement printed on screen for each empty line. Each blank line is resulting in a command not found.
I am running the script from the /var folder.
Here is the script:
#!/bin/bash
echo Hello World
I run it by typing the following:
bash testscript.sh
Why would this occur?
Make sure your first line is:
#!/bin/bash
Enter your path to bash if it is not /bin/bash
Try running:
dos2unix script.sh
That wil convert line endings, etc from Windows to unix format. i.e. it strips \r (CR) from line endings to change them from \r\n (CR+LF) to \n (LF).
More details about the dos2unix command (man page)
Another way to tell if your file is in dos/Win format:
cat scriptname.sh | sed 's/\r/<CR>/'
The output will look something like this:
#!/bin/sh<CR>
<CR>
echo Hello World<CR>
<CR>
This will output the entire file text with <CR> displayed for each \r character in the file.
You can use bash -x scriptname.sh to trace it.
I also ran into a similar issue. The issue seems to be permissions. If you do an ls -l, you may be able to identify that your file may NOT have the execute bit turned on. This will NOT allow the script to execute. :)
As #artooro added in comment:
To fix that issue run chmod +x testscript.sh
This might be trivial and not related to the OP's question, but I often made this mistaken at the beginning when I was learning scripting
VAR_NAME = $(hostname)
echo "the hostname is ${VAR_NAME}"
This will produce 'command not found' response. The correct way is to eliminate the spaces
VAR_NAME=$(hostname)
On Bash for Windows I've tried incorrectly to run
run_me.sh
without ./ at the beginning and got the same error.
For people with Windows background the correct form looks redundant:
./run_me.sh
If the script does its job (relatively) well, then it's running okay. Your problem is probably a single line in the file referencing a program that's either not on the path, not installed, misspelled, or something similar.
One way is to place a set -x at the top of your script or run it with bash -x instead of just bash - this will output the lines before executing them and you usually just need to look at the command output immediately before the error to see what's causing the problem
If, as you say, it's the blank lines causing the problems, you might want to check what's actaully in them. Run:
od -xcb testscript.sh
and make sure there's no "invisible" funny characters like the CTRL-M (carriage return) you may get by using a Windows-type editor.
use dos2unix on your script file.
for executing that you must provide full path of that
for example
/home/Manuel/mywrittenscript
Try chmod u+x testscript.sh
I know it from here:
http://www.linuxquestions.org/questions/red-hat-31/running-shell-script-command-not-found-202062/
If you have Notepad++ and you get this .sh Error Message: "command not found"
or this autoconf Error Message "line 615:
../../autoconf/bin/autom4te: No such file or directory".
On your Notepad++, Go to Edit -> EOL Conversion then check Macinthos(CR).
This will edit your files. I also encourage to check all files with this command,
because soon such an error will occur.
Had the same problem. Unfortunately
dos2unix winfile.sh
bash: dos2unix: command not found
so I did this to convert.
awk '{ sub("\r$", ""); print }' winfile.sh > unixfile.sh
and then
bash unixfile.sh
Problems with running scripts may also be connected to bad formatting of multi-line commands, for example if you have a whitespace character after line-breaking "\". E.g. this:
./run_me.sh \
--with-some parameter
(please note the extra space after "\") will cause problems, but when you remove that space, it will run perfectly fine.
I was also having some of the Cannot execute command. Everything looked correct, but in fact I was having a non-breakable space right before my command which was ofcourse impossible to spot with the naked eye:
if [[ "true" ]]; then
highlight --syntax js "var i = 0;"
fi
Which, in Vim, looked like:
if [[ "true" ]]; then
highlight --syntax js "var i = 0;"
fi
Only after running the Bash script checker shellcheck did I find the problem.
I ran into this today, absentmindedly copying the dollar command prompt $ (ahead of a command string) into the script.
Make sure you havenĀ“t override the 'PATH' variable by mistake like this:
#!/bin/bash
PATH="/home/user/Pictures/"; # do NOT do this
This was my mistake.
Add the current directory ( . ) to PATH to be able to execute a script, just by typing in its name, that resides in the current directory:
PATH=.:$PATH
You may want to update you .bashrc and .bash_profile files with aliases to recognize the command you are entering.
.bashrc and .bash_profile files are hidden files probably located on your C: drive where you save your program files.