We usually use $ as prompt in code block to demonstrate shell commands:
$ echo "hello world" > foo.md
$ cat foo.md
hello world
The problem is that you can't copy and paste those two lines with prefixed $ into your Terminal and execute them.
bash: $: command not found
However, I accidentally found that you can use prefixed ! for your commands (and prefixed # for outputs as comments)
! echo "hello world" > foo.md
! cat foo.md
# hello world
! ls
Now you can copy and paste above 4 lines into your shell and execute them at once.
Is that true? Is it worth to use ! for demonstration within code blocks in markdown files?
What does prefixed exclamation mark (!) command mean/do in shell?
As #chepner mentions below, the standalone ! is acting as a logical not operator.
Beyond that, traditionally the $ prefix indicates that the command should be run as an unprivileged user and the # prefix indicates that the command should run as a privileged user (root). See this answer for some more info.
Related
Below I have an example which confuses me a bit, any help would be appreciated.
I bind a normal command line command (ls) to a new variable. If I echo it it the output is just the command (ls) but if I just use the variable without echo i get the result of the command but why?? Is it because $listdir gets translated to ls so I just get the output? And if I use the echo command it will be interpreted as a string?
router#test:~/scripting$ listdir=ls
router#test:~/scripting$ echo "$listdir"
ls
----- VS ----
router#test:~/scripting$ $listdir
basicLoop.sh fileflood.sh .......
Thank you for any help!
By doing listdir=ls you literally assign a string "ls" to the $listdir variable. So if you run echo $listdir now it will just expand into echo ls, which (as you may have guessed) will just print "ls" onto a screen. If you want to store a result of a command into a variable you can wrap the command in `` or $() (eg. listdir=$(ls) or listdir=`ls`).
jarmusz#emacs~$ listdir=`ls`
jarmusz#emacs~$ echo "$listdir"
dls
docs
music
...
If you want to store just a name of the command and run it later you can do it like this:
jarmusz#emacs~$ listdir=ls
<some other commands...>
jarmusz#emacs~$ echo `$listdir`
dls docs music ...
In this example, echo `$listdir` will expand into echo `ls` and then into echo dls docs music...
When bash is interpreting the commands you feed to it, the first thing it will do is expand any expansions it is given. So when you give it $listdir by the time bash starts to execute the value it is given, all it knows is that it was given the value ls. It does not care where the value came from, only what the value is.
Lets look at the trace given after running set -x, which instructs bash to prints to stderr after expansion and before execution:
$> echo $listdir
+ echo ls
ls
$> $listdir
+ ls
file_0 file_1
As you can see, in the second line, bash will attempt to run the command ls just as if you have explicity called ls or even /usr/bin/ls
Edit
Expansion isn't the first step in in shell evaluation, see #Gordon Davisson's comment for details
In my program I need to know the maximum number of process I can run. So I write a script. It works when I run it in shell but but when in program using system("./limit.sh"). I work in bash.
Here is my code:
#/bin/bash
LIMIT=\`ulimit -u\`
ACTIVE=\`ps -u | wc -l \`
echo $LIMIT > limit.txt
echo $ACTIVE >> limit.txt
Anyone can help?
Why The Original Fails
Command substitution syntax doesn't work if escaped. When you run:
LIMIT=\`ulimit -u\`
...what you're doing is running a command named
-u`
...with the environment variable named LIMIT containing the value
`ulimit
...and unless you actually have a command that starts with -u and contains a backtick in its name, this can be expected to fail.
This is because using backticks makes characters which would otherwise be syntax into literals, and running a command with one or more var=value pairs preceding it treats those pairs as variables to export in the environment for the duration of that single command.
Doing It Better
#!/bin/bash
limit=$(ulimit -u)
active=$(ps -u | wc -l)
printf '%s\n' "$limit" "$active" >limit.txt
Leave off the backticks.
Use modern $() command substitution syntax.
Avoid multiple redirections.
Avoid all-caps names for your own variables (these names are used for variables with meaning to the OS or system; lowercase names are reserved for application use).
Doing It Right
#!/bin/bash
exec >limit.txt # open limit.txt as output for the rest of the script
ulimit -u # run ulimit -u, inheriting that FD for output
ps -u | wc -l # run your pipeline, likewise with output to the existing FD
You have a typo on the very first line: #/bin/bash should be #!/bin/bash - this is often known as a "shebang" line, for "hash" (#) + "bang" (!)
Without that syntax written correctly, the script is run through the system's default shell, which will see that line as just a comment.
As pointed out in comments, that also means only the standardised options available to the builtin ulimit command, which doesn't include -u.
$ echo Hello world > file
$ echo Hello > file world
$ echo > file Hello world
$ > file echo Hello world
They all do the same thing, but I do not know why.
From man bash:
Simple Commands
A simple command is a sequence of optional variable assignments fol-
lowed by blank-separated words and redirections, and terminated by a
control operator. The first word specifies the command to be executed,
and is passed as argument zero. The remaining words are passed as
arguments to the invoked command.
That is, it doesn't specify the ordering of the "words and redirections".
Later in the REDIRECTIONS section:
REDIRECTION
[...]
The [...] redirection opera-
tors may precede or appear anywhere within a simple command or may fol-
low a command. Redirections are processed in the order they appear,
from left to right.
[...]
So they can appear anywhere.
And as you yourself have observed too, there's no difference between them in terms of the result.
There is a difference however in readability.
This is the most intuitive way of writing it:
echo Hello world > file
Really easy to understand. The > looks like an arrow, doesn't it.
The others are not so intuitive, less readable.
I suggest to stick to the first writing style.
Let's take a little example:
$ cat source.sh
#!/bin/bash
echo "I'm file source-1"
. source-2.sh
And:
$ cat source-2.sh
#!/bin/bash
echo "I'm file source-2"
Now run:
$ ./source.sh
I'm file source-1
I'm file source-2
If I'll change the call of the second file in first:
$ cat source.sh
#!/bin/bash
echo "I'm file source-1"
source source-2.sh
It will have the same effect as using dot.
What is difference between these methods?
The only difference is in portability.
. is the POSIX-standard command for executing commands from a file; source is a more-readable synonym provided by Bash and some other shells. Bash itself, however, makes no distinction between the two.
There is no difference.
From the manual:
source
source filename
A synonym for . (see Bourne Shell Builtins).
Is there any bash trick that allows giving some parameters in command line to a program that gets its inputs via input stream? Something like this:
program < 'a=1;b=a*2;'
but < needs a file input stream.
For very short here-documents, there are also here-strings:
program <<< "a=1;b=a*2"
I think
echo 'a=1;b=a*2;' | program
is what you need. This process is called "piping"
As a side note: doing the opposite (i.e. piping other programs output as arguments) could be done with xargs
echo works great. The other answer is Here-documents [1]
program <<EOF
a=1;b=a*2;
EOF
I use echo when I have one very short thing on one line, and heredocs when I have something that requires newlines.
[1] http://tldp.org/LDP/abs/html/here-docs.html
shopt -s expand_aliases
alias 'xscript:'='<<:ends'
xscript: bc | anotherprog | yetanotherprog ...
a=1;b=a*2;
:ends
Took me a year to hack this one out. Premium bash script here fellas. Give respect where due please :)
I call this little 'diddy' xscript because you can expand bash variables and substitutions inside of the here document.
alias 'script:'='<<":ends"'
The above version does not expand substitutions.
xscript: cat
The files in our path are: `ls -A`
:ends
script: cat
The files in our path are: `ls -A`
:ends
I'm not finished!
source <(xscript: cat
echo \$BASH "hello world, I'mma script genius!"
echo You can thank me now $USER
:ends
)