Shell Scripting How to combine variables and wildcard - shell

I have a simple shell script to run several commands at once. I can't figure out how to do this:
'mkdir -p $FULL_BACKUP_PATH; cp -r $FULL_PATH/* $FULL_BACKUP_PATH/.;'
If I use single quotes, the variables don't get the values, if I use double quotes, the wildcard does not expand.
Please help
Thanks

I think you want this:
mkdir -p "${FULL_BACKUP_PATH}"; cp -r "${FULL_PATH}/*" "${FULL_BACKUP_PATH}"
Variables inside double quotes get expanded, variables inside single quotes do not. Always put variables inside double quotes if they are paths/directories in case they have spaces in them so the double quotes "hold them together".
If the code appears in shell script that starts with a shebang like this:
#!/bin/bash
you can temporarily add -xv after bash to see the script expanded as it is executed and that will help you debug it, like this:
#!/bin/bash -xv

Related

Difference in behavior of directly invoking a shell script and exec it?

I have a file path to a script in a shell variable that if run it directly, it runs fine (the path has a whitespace escaped with a \ there is a white space after the \), but when I try via
exec $script "$#"
the whitespace becomes in the script path becomes an issues and breaks the path to the script. How can I fix this? (I can't change the given path that has a whitespace in it)
Don't put backslashes into the variable. Quote its expansion.
script="is/already a/string"
exec "$script" "$#"

How to use a shell variable inside sed when doing "d" command?

In my bash, I wish to delete lines from 1 to ${number}, like this:
number=10
sed '1,${number}d' myfile
It failed with syntax error.
I also tried "\${number}", '"$number"', neithers works
I changed to double quote, it works under command line, but not inside bash script file. How to make it work?
Enclose your sed expression in double quotes to interpolate the variable number:
sed "1,${number}d" file
Please use double quotes instead of single quotes while running sed this way.
Read here for Difference between single and double quotes
I changed to double quote, it works under command line, but not inside
bash script file
Assuming your bash script is:
sed "1,${number}d" myfile
you should export number variable in bash prompt so that it can be visible in bash script when it is run:
export number=10

Heredoc without quotes not expanding parameters

I am trying to create and use variables inside heredoc like this,
#!bin/bash
sudo su - postgres <<EOF
IP="XYZ"
echo "$IP"
EOF
This doesn't work right and I get a blank line as echo.
But if I use quotes around EOF like this,
#!bin/bash
sudo su - postgres <<"EOF"
IP="XYZ"
echo "$IP"
EOF
It works. Can someone please explain this? According to what I read in man the behaviour should be opposite.
The shell evaluates the unquoted here document and performs variable interpolation before passing it to the command (in your case, sudo). Because IP is not a defined variable in the parent shell, it gets expanded to an empty string.
With quotes, you prevent variable interpolation by the parent shell, and so the shell run by sudo sees and expands the variable.

"bash -c" doesn't export vars from sourced scripts

I have an inclusion file test.inc:
export XXX=xxx
I use it when call bash to interpret a string:
bash -c ". test.inc; echo $XXX"
But the variable is not set at the point of echo command. If I do 'export' I can see it though:
bash -c ". test.inc; export"
Shows
declare -x XXX="XXX"
How do I make my first command see the exported variables from sourced files when I use bash -c syntax?
You are using double quotes. Therefore your current shell expands $XXX long before the bash -c instance sees it. Switch to single quotes, or escape the dollar sign.

emacs --eval '(ediff "$1" "$2")' how to put this line in to shell-script?

I want to put the following line:
emacs --eval '(ediff "$1" "$2")'
into a shell script, so I dont need to write this long and complicated line everytime. However, when I put it into my shell script as it is, I get an error:
ediff-find-file: File `$1' does not exist or is not readable
I guess there is some sort of " escaping problem here and I need to put some \ in this line. What exactly do I need to fix?
This is normal, your string is surrounded with single quotes, and variables are not expanded within single quotes.
You should use double quotes so that they get expanded, and escape existing double quotes in the string:
emacs --eval "(ediff \"$1\" \"$2\")"
It is worth noting that when expanding variables, only the outer quotes matter. That is:
$ A=foo
$ echo "'$A'"
will print 'foo'. The fact that single quotes surround $A here does not matter: the outer quotes are double quotes.
Your immediate problem is that the single quotes prevent all expansion by the shell. You need double quotes for any kind of expansion to happen. However, you can't just write emacs --eval "(ediff \"$1\" \"$2\")" because the file names would not be properly quotes for Emacs, so your script would break if the file names contained " or \.
Fortunately, there's a very simple solution:
emacs --eval '(ediff command-line-args-left)' "$#"
It would be better to reuse an existing Emacs process if there is one, by calling emacsclient. Unfortunately, with Emacsclient, --eval treats all its arguments as Lisp expressions. So you need to do the quoting inside the shell. In bash or ksh, you can use ${VARIABLE//PATTERN/REPLACEMENT} to add backslashes before the double quotes and backslashes; it's a little painful but it works.
quoted1=${1//\\/\\\\}; quoted1=${quoted1//\"/\\\"}
quoted2=${2//\\/\\\\}; quoted2=${quoted2//\"/\\\"}
emacsclient -a '' --eval "(ediff \"$quoted1\" \"$quoted2\")"
To have an easy function called "ediff" in my $HOME/.profile I combined two tips together. The one from Gilles above and from the defunitive blog. I added the -c argument for emacsclient and emacs as the fallback editor:
ediff () {
if [ "X${2}" = "X" ]
then
echo "USAGE: ediff <FILE 1> <FILE 2>"
else
quoted1=${1//\\/\\\\};quoted1=${quoted1//\"/\\\"}
quoted2=${2//\\/\\\\};quoted2=${quoted2//\"/\\\"}
emacsclient -c -a emacs -e "(ediff \"$quoted1\" \"$quoted2\")"
fi
}

Resources