smbclient copy file with single quote - linux

how can i use single quote in smbclient "put" command?
For example:
smbclient -c 'put "/mydir/video.avi" "\Music\Guns N' Roses\video.avi"'
The ' in "Guns N' Roses" generate an error, but i cannot use "Guns N\' Roses", because will change path.

Your shell doesn't allow use of escaped single quotes inside a single-quoted string. Read the section entitled "QUOTING" in man bash (assuming your shell is bash).
You need to escape the inner single quotes outside the single-quoted string:
smbclient -c 'put "/mydir/video.avi" "\Music\Guns N'\'' Roses\video.avi"'
Or, if you prefer:
smbclient -c 'put "/mydir/video.avi" "\Music\Guns N'"'"' Roses\video.avi"'
Or alternately, you could put things in variables, use formatting, etc. Obviously I haven't tested this in your environment, but the following seems reasonable to me:
$ source="/mydir/video.avi"
$ target="\Music\Guns N' Roses\video.avi"
$ cmd='put "$s" "$s"'
$ smbclient -c "$(printf "$cmd" "$source" "$target")"

Related

Bash escape character

I have this very reduced example of a bash command, where I want the $ sign escaped.
So the command :
su -m user -c "echo $test"
should print out:
$test
a simple \$test does not work unfortunately. I tried lots of other stuff but still couldn't find a solution. Any suggestions ?
Put it in single quotes rather than double quotes.
su -m user -c 'echo \$test='
The single quotes keep the variable from being expanded by the original shell. The backslash then escapes the dollar sign in the shell run by su.
See Difference between single and double quotes in Bash
In answer to the comment, you can switch to double quoting to get single quotes into the string.
su -m user -c 'echo \$test='"'1'"

Remote SSH : no such file or directory

When trying to run this cmd:
ssh user#host " cp -f /path1/`cat /path2/file.txt | awk -F : '{printf $4}' `* ../ "
got this:
cat: /path2/file.txt: no such file or directory
Notice that when execute it directly in the server it works
Thanks for any advice
Try this:
ssh user#host 'cp -f /path1/$(awk -F : '\''{printf $4}'\'' /path2/file.txt)* ..'
This might be also interesting: Useless Use of Cat Award.
Or this:
ssh user#host 'cp -f '\'"$path1"\''/$(awk -F : '\''{printf $4}'\'' /path2/file.txt)* ..'
Keep in mind:
Singe quotes do not evaluate $.
Double quotes do evaluate $.
If you want to put a single quote into a single quoted string, you have to split the string in two parts and put an escaped single quote in between. 'a'\''b' becomes a'b
If you need to evaluate a variable in a single quoted string, you have to split the string in two parts and put the double quoted variable in between. 'a'"$x"'b' becomes a${x}b

bash escape exclamation character inside variable with backtick

I have this bash script:
databases=`mysql -h$DBHOST -u$DBUSER -p$DBPASSWORD -e "SHOW DATABASES;" | tr -d "| " | grep -v Database`
and the issue is when the password has all the characters possible. how can i escape the $DBPASSWORD in this case? If I have a password with '!' and given the fact that command is inside backticks. I have no experience in bash scripts but I've tried with "$DBPASSWORD" and with '$DBPASSWORD' and it doesn't work. Thank you
LATER EDIT: link to script here, line 170 -> https://github.com/Ardakilic/backmeup/blob/master/backmeup.sh
First: The answer from #bishop is spot on: Don't pass passwords on the command line.
Second: Use double quotes for all shell expansions. All of them. Always.
databases=$(mysql -h"$DBHOST" -u"$DBUSER" -p"$DBPASSWORD" -e "SHOW DATABASES;" | tr -d "| " | grep -v Database)
Don't pass the MySQL password on the command line. One, it can be tricky with passwords containing shell meta-characters (as you've discovered). Two, importantly, someone using ps can sniff the password.
Instead, either put the password into the system my.cnf, your user configuration file (eg .mylogin.cnf) or create an on-demand file to hold the password:
function mysql() {
local tmpfile=$(mktemp)
cat > "$tmpfile" <<EOCNF
[client]
password=$DBPASSWORD
EOCNF
mysql --defaults-extra-file="$tmpfile" -u"$DBUSER" -h"$DBHOST" "$#"
rm "$tmpfile"
}
Then you can run it as:
mysql -e "SHOW DATABASES" | tr -d "| " ....
mysql -e "SELECT * FROM table" | grep -v ...
See the MySQL docs on configuration files for further examples.
I sometimes have the same problem when automating activities:
I have a variable containing a string (usually a password) that is set in a config file or passed on the command-line, and that string includes the '!' character.
I need to pass that variable's value to another program, as a command-line argument.
If I pass the variable unquoted, or in double-quotes ("$password"), the shell tries to interpret the '!', which fails.
If I pass the variable in single quotes ('$password'), the variable isn't expanded.
One solution is to construct the full command in a variable and then use eval, for example:
#!/bin/bash
username=myuser
password='my_pass!'
cmd="/usr/bin/someprog -user '$username' -pass '$password'"
eval "$cmd"
Another solution is to write the command to a temporary file and then source the file:
#!/bin/bash
username=myuser
password='my_pass!'
cmd_tmp=$HOME/.tmp.$$
touch $cmd_tmp
chmod 600 $cmd_tmp
cat > $cmd_tmp <<END
/usr/bin/someprog -user '$username' -pass '$password'
END
source $cmd_tmp
rm -f $cmd_tmp
Using eval is simple, but writing a file allows for multiple complex commands.
P.S. Yes, I know that passing passwords on the command-line isn't secure - there is no need for more virtue-signalling comments on that topic.

Escape quotes inside su -c

I would like to pass a path potentially containing whitespace into an su -c command inside a .sh script:
su -c "xdg-desktop-menu install ${DesktopFile}" -m "${Username}"
$DesktopFile is my path that needs to get escaped. I tried many variations with ' inside "", with \" and several braces, but I have not come up with a solution. Interestingly enough, xdg-desktop-icon works fine, but xdg-desktop-menu dies at the whitespace. Any suggestions?
If you're using bash, printf '%q' can be used to escape special characters when quoting is insufficient.
su -c "xdg-desktop-menu install $(printf '%q' "$DesktopFile") -m $(printf '%q' "$Username")"
Notice that $(printf...) doesn't need quotes, but "$DesktopFile" does. The variable needs to be passed to printf safely, so it has to be quoted. printf '%q''s output is guaranteed to be immune to word splitting and globbing, so it doesn't need quotes. (Although, if you wanted to quote it, you could. It would need \" on either side.)
i can't make out if this is a bug in xdg-desktop-menu, since it works in xdg-desktop-icon, nevertheless there is a workaround I am now using:
cd "$PathWithSpaces"
su -c "xdg-desktop-menu install $DesktopFilenameWithoutSpaces" -m "$Username"
PathWithSpaces contains DesktopFilenameWithoutSpaces, seems to work reliably.

Extract all variable values in a shell script

I'm debugging an old shell script; I want to check the values of all the variables used, it's a huge ugly script with approx more than 140 variables used. Is there anyway I can extract the variable names from the script and put them in a convenient pattern like:
#!/bin/sh
if [ ${BLAH} ....
.....
rm -rf ${JUNK}.....
to
echo ${BLAH}
echo ${JUNK}
...
Try running your script as follows:
bash -x ./script.bash
Or enable the setting in the script:
set -x
You can dump all interested variables in one command using:
set | grep -w -e BLAH -e JUNK
To dump all the variables to stdout use:
set
or
env
from inside your script.
You can extract a (sub)list of the variables declared in your script using grep:
grep -Po "([a-z][a-zA-Z0-9_]+)(?==\")" ./script.bash | sort -u
Disclaimer: why "sublist"?
The expression given will match string followed by an egal sign (=) and a double quote ("). So if you don't use syntax such as myvar="my-value" it won't work.
But you got the idea.
grep Options
-P --perl-regexp: Interpret PATTERN as a Perl regular expression (PCRE, see below) (experimental) ;
-o --only-matching: Print only the matched (non-empty) parts of a matching line, with each such part on a separate output line.
Pattern
I'm using a positive lookahead: (?==\") to require an egal sign followed by a double quote.
In bash, but not sh, compgen -v will list the names of all variables assigned (compare this to set, which has a great deal of output other than variable names, and thus needs to be parsed).
Thus, if you change the top of the script to #!/bin/bash, you will be able to use compgen -v to generate that list.
That said, the person who advised you use set -x did well. Consider this extension on that:
PS4=':$BASH_SOURCE:$LINENO+'; set -x
This will print the source file and line number before every command (or variable assignment) which is executed, so you will have a log not only of which variables are set, but just where in the source each one was assigned. This makes tracking down where each variable is set far easier.

Resources