I am just unable to search this in question list. Please help me here to find if someone already asked.
I am doing ssh on various m/c with filename like "/a/b/file$$$$".
ssh $host "/a/b/file$$$$"
is now been replaced with
ssh $host "/a/b/file54645464"
above is the proc id of the bash scrpt which i am running.
so the issue is that later queries couldn't find this
any pointer will be of great help.
Try
ssh $host '/a/b/file$$$$'
Quoting with ' instead of " prevents variable substitution.
From the manpage (section QUOTING):
Enclosing characters in single quotes preserves the literal value of each character within the quotes.
The variable substituted in your case is $:
$
Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell.
Since a $ sign is (also) used to access the value of the $ variable every pair ($$) is substituted with the process ID and that is why you end up with twice the process id.
use single quotes to have $ not expanded:
$> echo '$ok'
$ok
Related
my bash script looks like:
#!/bin/sh
set -e
cat <<EOF > config.json
{
"host": "READER",
"server-url": "${server.url}",
"port": 8080,
}
EOF
when I run the file via ./generateJson.sh or bash generateJson.sh then I get the error
line 5: ..... : bad substitution
I have set the local variable server.url.
if I run echo $server.url in the same terminal session it has a string assigned.
what does the bad substitution error mean?
why is this happening?
I have seen many posts saying to use #!/bin/bash or other ways of making sure that it is running on bash not dash. But this makes no difference.
Variables in bash (or /bin/sh) can not contain dots in their names. This means that ${server.url} can not be expanded, and since it does not correspond to a know parameter substitution syntax, the shell complains with the error that you see.
Choose another name for your variable, e.g. server_url.
If your variable is actually called server and you want to add .url to its value, use $server.url in the here-document.
If you want to insert the literal string ${server.url} in the document, then either escape the $ as \$, or use 'EOF' or \EOF to quote the whole here-document (only at the start, not at the end).
I have some inconsistent behavior in my bash script.
There are variables, and all of them have values assigned to them, I confirm them by echoing the values at the beginning of the script.
However, when passing them to a remote SSH session, one variable has value, whereas the other one appear to be blank. I am pretty sure I am not overwriting the variable's value.
# Script input arguments
USER=$1
SERVER=$2
# Other vars
PFX=$8
#
ADDRESS=$USER#$SERVER
function run {
ssh $ADDRESS /bin/bash $#
}
# Script body, some stuff happens here
run << "SSHCONNECTION2"
sudo mv "/home/$USER/$PFX" "/home/$USER/certs/"
SSHCONNECTION2
So, the output of mv is
error 03-Jan-2017 17:20:39 mv: cannot move '/home/admin/' to a subdirectory of itself, '/home/admin/certs/admin'
Can somebody give me a hint what am I doing wrong?
Thank you.
USER had a remote value because USER always has a value: By default, it's the current user account on all POSIX systems. To avoid conflicting with system-defined variable names, you should use lower-case names for your own shell and environment variables (the former because setting a shell variable with a name that overlaps an environment variable will implicitly overwrite the latter).
#!/bin/bash
# ^^^^ - not /bin/sh; printf %q (thus, eval-safe quoting) is a bash extension
user=$1
pfx=$8
# Tell the shell to quote your variables to be eval-safe!
printf -v user_q '%q' "$user"
printf -v pfx_q '%q' "$pfx"
# ...then you can use those eval-safe version in your heredoc
run << SSHCONNECTION2
# because the values are self-quoted, don't put their expansions inside quotes
sudo mv /home/$user_q/$pfx_q /home/$user_q/certs/
SSHCONNECTION2
Notes:
The sigil (SSHCONNECTION2) is intentionally unquoted to allow expansions to occur.
Using lower-case variable names avoids inadvertently conflicting with names meaningful to the shell or system.
The above is a bit unfortunate, because the literal contents of the SSHCONNECTION2 heredoc isn't code that could safely be run directly in a shell. Consider this answer instead.
I am trying to edit my .bashrc file with a custom function to launch xwin. I want it to be able to open in multiple windows, so I decided to make a function that accepts 1 parameter: the display number. Here is my code:
function test(){
a=$(($1-0))
"xinit -- :$a -multiwindow -clipboard &"
}
The reason why I created a variable "a" to hold the input is because I suspected that the input was being read in as a string and not a number. I was hoping that taking the step where I subtract the input by 0 would convert the string into an integer, but I'm not actually sure if it will or not. Now, when I call
test 0
I am given the error
-bash: xinit -- :0 -multiwindow -clipboard &: command not found
How can I fix this? Thanks!
Because the entire quoted command is acting as the command itself:
$ "ls"
a b c
$ "ls -1"
-bash: ls -1: command not found
Get rid of the double quotation marks surrounding your xinit:
xinit -- ":$a" -multiwindow -clipboard &
In addition to the double-quotes bishop pointed out, there are several other problems with this function:
test is a standard, and very important, command. Do not redefine it! If you do, you risk having some script (or sourced file, or whatever) run:
if test $num -eq 5; then ...
Which will fire off xinit on some random window number, then continue the script as if $num was equal to 5 (whether or not it actually is). This way lies madness.
As chepner pointed out in a comment, bash doesn't really have an integer type. To it, an integer is just a string that happens to contain only digits (and maybe a "-" at the front), so converting to integer is a non-opertation. But what you might want to do is check whether the parameter got left off. You can either check whether $1 is empty (e.g. if [[ -z "$1" ]]; then echo "Usage: ..." >&2 etc), or supply a default value with e.g. ${1:-0} (in this case, "0" is used as the default).
Finally, don't use the function keyword. bash tolerates it, but it's nonstandard and doesn't do anything useful.
So, here's what I get as the cleaned-up version of the function:
launchxwin() {
xinit -- ":${1:-0}" -multiwindow -clipboard &
}
That happens because bash interprets everything inside quotes as a String. A command is an array of strings which the first element is a binary file or a internal shell command. Subsequent strings in the array are taken as argument.
When you type:
"xinit -- :$a -multiwindow -clipboard &"
the shell thinks that everything you wrote is a command. Depending on the command/program you ran all the rest of the arguments can be a single string. But mostly you use quotes only if you are passing a argument that has spaces inside like:
mkdir "My Documents"
That creates a single directory named My Documents. Also, you could escape spaces like this.
mkdir My\ Documents
But remember, "$" is a special character like "\". It gets interpreted by the shell as a variable. "$a" will be substituted by its value before executing. If you use a simple quote ('$a') it will not be interpreted by the shell.
Also, "&" is a special character that executes the command in background. You should probably pass it outside the quotes also.
So I have a script where I type the script.sh followed by input for a set of if-else statements. Like this:
script.sh fnSw38h$?2
The output echoes out the input in the end.
But I noticed that $? is interpreted as 0/1 so the output would echo:
fnSw38h12
How can I stop the shell from expanding the characters and take it face value?
I looked at something like opt noglob or something similar but they didn't work.
When I put it like this:
script.sh 'fnSw38h$?2'
it works. But how do I capture that within single quotes ('') when I can't state variables inside it like Var='$1'
Please help!
How to pass a password to a script
I gather from the comments that the true purpose of this script is to validate a password. If this is an important or sensitive application, you really should be using professional security tools. If this application is not sensitive or this is just a learning exercise, then read on for a first introduction to the issues.
First, do not do this:
script.sh fnSw38h$?2
This password will appear in ps and be visible to any user on the system in plain text.
Instead, have the user type the password as input to the script, such as:
#!/bin/sh
IFS= read -r var
Here, read will gather input from the keyboard free from shell interference and it will not appear in ps output.
var will have the password for you to verify but you really shouldn't have plain text passwords saved anywhere for you to verify against. It is much better to put the password through a one-way hash and then compare the hash with something that you have saved in a file. For example:
var=$(head -n1 | md5sum)
Here, head will read one line (the password) and pass it to md5sum which will convert it to a hash. This hash can be compared with the known correct hash for this user's password. The text returned by head will be exactly what the user typed, unmangled by the shell.
Actually, for a known hash algorithm, it is possible to make a reverse look-up table for common passwords. So, the solution is to create a variable, called salt, that has some user dependent information:
var=$( { head -n1; echo "$salt"; } | md5sum)
The salt does not have to be kept secret. It is just there to make look-up tables more difficult to compute.
The md5sum algorithm, however, has been found to have some weaknesses. So, it should be replaced with more recent hash algorithms. As I write, that would probably be a sha-2 variant.
Again, if this is a sensitive application, do not use home-made tools
Answer to original question
how do I capture that within single quotes ('') when I can't state variables inside it like Var='$1'
The answer is that you don't need to. Consider, for example, this script:
#!/bin/sh
var=$1
echo $var
First, note that $$ and $? are both shell variables:
$ echo $$ $?
28712 0
Now, let's try our script:
$ bash ./script.sh '$$ $?'
$$ $?
These variables were not expanded because (1) when they appeared on the command line, they were in single-quotes, and (2) in the script, they were assigned to variables and bash does not expand variables recursively. In other words, on the line echo $var, bash will expand $var to get $$ $? but there it stops. It does not expand what was in var.
You can escape any dollar signs in a double-quoted string that are not meant to introduce a parameter expansion.
var=foo
# Pass the literal string fnSw38h$?2foo to script.sh
script.sh "fnSw38h\$?2$var"
You cannot do what you are trying to do. What is entered on the command line (such as the arguments to your script) must be in shell syntax, and will be interpreted by the shell (according to the shell's rules) before being handed to your script.
When someone runs the command script.sh fnSw38h$?2, the shell parses the argument as the text "fnSw38h", followed by $? which means "substitute the exit status of the last command here", followed by "2". So the shell does as it's been told, it substitutes the exit status of the last command, then hands the result of that to your script.
Your script never receives "fnSw38h$?2", and cannot recover the argument in that form. It receives something like "fnSw38h02" or "fnSw38h12", because that's what the user asked the shell to pass it. That might not be what the user wanted to pass it, but as I said, the command must be in shell syntax, and in shell syntax an unescaped and unnquoted $? means "substitute the last exit status here".
If the user wants to pass "$?" as part of the argument, they must escape or single-quote it on the command line. Period.
I'm trying to populate a shell variable called $recipient which should contain a value followed by a new-line.
$ set -x # force bash to show commands as it executes them
I start by populating $user, which is the value that I want to be followed by the newline.
$ user=user#xxx.com
+ user=user#xxx.com
I then call echo $user inside a double-quoted command substitution. The echo statement should create a newline after $user, and the double-quotes should preserve the newline.
$ recipient="$(echo $user)"
++ echo user#xxx.com
+ recipient=user#xxx.com
However when I print $recipient, I can see that the newline has been discarded.
$ echo "'recipient'"
+ echo ''\''recipient'\'''
'recipient'
I've found the same behaviour under bash versions 4.1.5 and 3.1.17, and also replicated the issue under dash.
I tried using "printf" rather than echo; this didn't change anything.
Is this expected behaviour?
Command substitution removes trailing newlines. From the standard:
The shell shall expand the command substitution by executing command in a subshell environment (see Shell Execution Environment ) and replacing the command substitution (the text of command plus the enclosing "$()" or backquotes) with the standard output of the command, removing sequences of one or more characters at the end of the substitution. Embedded characters before the end of the output shall not be removed; however, they may be treated as field delimiters and eliminated during field splitting, depending on the value of IFS and quoting that is in effect. If the output contains any null bytes, the behavior is unspecified.
You will have to explicitly add a newline. Perhaps:
recipient="$user
"
There's really no reason to use a command substitution here. (Which is to say that $(echo ...) is almost always a silly thing to do.)
All shell versions will react the same way, this is nothing new in scripting.
The new-line at the end of your original assignment is not included in the variable's value. It only "terminates" the current cmd and signals the shell to process.
Maybe user="user#xxx.com\n" will work, but without context about why you want this, just know that people usually keep variables values separate from the formatting "tools" like the newline.
IHTH.