I am trying to run something like this from a bash script:
HOST=foo
DIR=bar
ssh user#$HOST "
function test
{
CURHOST=$HOST
cd $DIR
mkdir -p $CURHOST
}; test"
When I run it with set -x I see that it translates to this:
+ ssh user#foo '
function test
{
CURHOST=foo
cd bar
mkdir -p
}; test
and then of course it complains about mkdir -p having no argument. Why is this and how can I set a local variable in there?
To prevent substitution, you can use either single-quotes '...' or a backslash \; for example, this command:
echo '$foo' \$foo "\$foo"
will print this:
$foo $foo $foo
and will not use the variable foo.
In your case, rather than using "..." for the whole argument, you probably should use '...' everywhere except where you specifically need substitution. So:
HOST=foo
DIR=bar
ssh user#$HOST '
function test
{
CURHOST='"$HOST"'
cd $DIR
mkdir -p $CURHOST
}; test'
Just escape the dollar sign:
echo "
function test
{
CURHOST=$HOST
cd $DIR
mkdir -p \$CURHOST
}; test"
gives you:
function test
{
CURHOST=foo
cd bar
mkdir -p $CURHOST
}; test
Related
I've been working through creating a script to move some files from a local machine to a remote server. As part of that process I have a function that can either be called directly or wrapped with 'declare -fp' and sent along to an ssh command. The code I have so far looks like this:
export REMOTE_HOST=myserver
export TMP=eyerep-files
doTest()
{
echo "Test moving files from $TMP with arg $1"
declare -A files=(["abc"]="123" ["xyz"]="789")
echo "Files: ${!files[#]}"
for key in "${!files[#]}"
do
echo "$key => ${files[$key]}"
done
}
moveTest()
{
echo "attempting move with wrapped function"
ssh -t "$REMOTE_HOST" "$(declare -fp doTest|envsubst); doTest ${1#Q}"
}
moveTest $2
If I run the script with something like
./myscript.sh test dev
I get the output
attempting move with wrapped function
Test moving files from eyerep-files with arg dev
Files: abc xyz
bash: line 7: => ${files[]}: bad substitution
It seems like the string expansion for the for loop is not working correctly. Is this expected behaviour? If so, is there an alternative way to loop through an array that would avoid this issue?
If you're confident that your remote account's default shell is bash, this might look like:
moveTest() {
ssh -t "$REMOTE_HOST" "$(declare -f doTest; declare -p $(compgen -e)); doTest ${1#Q}"
}
If you aren't, it might instead be:
moveTest() {
ssh -t "$REMOTE_HOST" 'exec bash -s' <<EOF
set -- ${##Q}
$(declare -f doTest; declare -p $(compgen -e))
doTest \"\$#\"
EOF
}
I managed to find an answer here: https://unix.stackexchange.com/questions/294378/replacing-only-specific-variables-with-envsubst/294400
Since I'm exporting the global variables, I can get a list of them using compgen and use that list with envsubst to specify which variables I want to replace. My finished function ended up looking like:
moveTest()
{
echo "attempting move with wrapped function"
ssh -t "$REMOTE_HOST" "$(declare -fp doTest|envsubst "$(compgen -e | awk '$0="${"$0"}"') '${1}'"); doTest ${1#Q}"
}
The following two .sh files are my code.
If I don't use $* everything works, but if I use $* it will prompt "./test2.sh:line 8: C: / Program: No such file or directory".
I use cygwin on windows to run test.sh file.
test.sh
#!/bin/sh
UNITY_PATH="C:/Program Files/Unity/Hub/Editor/2018.4.14f1/Editor/Unity.exe"
BUILD_ANDROID_RES=./test2.sh
${BUILD_ANDROID_RES} \
-UnityPath "${UNITY_PATH}" \
test2.sh with $*
#!/bin/sh
parse_arguments() {
UNITY_PATH=$2
}
build_android_assetbundle() {
echo "aaa ${UNITY_PATH}"
"${UNITY_PATH}" abc
}
parse_arguments $*
build_android_assetbundle
test2.sh without $*
#!/bin/sh
build_android_assetbundle() {
echo "aaa ${UNITY_PATH}"
"${UNITY_PATH}" abc
}
UNITY_PATH=$2
build_android_assetbundle
I hope to be able to use $ *, who can solve this problem? Thank you.
I have tried in many ways but couldn't get it the right way.
fun="
mkcdo ()
{
mkdir -p -- \"'$1'\" && cd -P -- \"'$1'\"
}"
echo "$fun" >> ~/.bashrc
What I want is to append this in .bashrc
mkcd ()
{
mkdir -p -- "$1" && cd -P -- "$1"
}
Could that be done? Is there a way in bash like there is in python: r'whatever\you\$write' so that it is completely ignored as simple text?
Using a variable to store a bash function code sounds much of anti-pattern. For multi-line formatted strings, I would recommend using here-doc and quote them to avoid expanding the variable,
cat >> ~/.bashrc << 'EOF'
mkcd () {
mkdir -p -- "$1" && cd -P -- "$1"
}
EOF
Further reading - Bash - Here documents
Alternative1: just use single quotes.
fun='
mkcdo ()
{
mkdir -p -- "$1" && cd -P -- "$1"
}'
echo "$fun" >> ~/.bashrc
Alternative2: escape the $ sign.
fun="
mkcdo ()
{
mkdir -p -- \"\$1\" && cd -P -- \"\$1\"
}"
echo "$fun" >> ~/.bashrc
I am trying to create directory at user's home directory using a shell script. The script has following line:
mkdir -p $path # where path=~/adirectory, path is obtained from env
but instead of creating it at user's home directory i.e. /home/auser/adirectory, it creates a directory named ~ at current working directory and places adirectory inside it.
Update:
Thanx to Jonathan Leffler for helping out. Below is the working snippet of my code:
function init() {
if [ "$PROJECT_DIR" = "" ]; then
export PROJECT_DIR=$HOME/projects
fi
mkdir -p `expand $PROJECT_DIR`
}
function expand(){
echo `sh -c "echo $1"`
}
As Jonathan Leffler pointed, the problem was with tilde expansion. Using sh -c $path worked for me.
The problem was with tilde expansion. Using sh -c $path worked for me.
function init() {
if [ "$PROJECT_DIR" = "" ]; then
export PROJECT_DIR=$HOME/projects
fi
mkdir -p `expand $PROJECT_DIR`
}
function expand(){
echo `sh -c "echo $1"`
}
I've been trying several fails to perform the following:
Basically, what I need is to execute several sequenced commands on a remote unix shell, such as setting environment variables with variables that I have on the script, move to a particular directory and run a script there and so on.
I've tried using a printf with the portion of the script and then piped the ssh command, but it didn't work quite well, also, I've read about the "ssh ... >> END" marker, which is great but since I'm using functions, it doesn't work well.
Do you have any thoughts?
Here's an excerpt of the code:
deployApp() {
inputLine=$1;
APP_SPECIFIC_DEPLOY_SCRIPT="$(echo $inputLine | cut -d ' ' -s -f1)";
BRANCH="$(echo $inputLine | cut -d ' ' -s -f2)";
JBOSS_HOME="$(echo $inputLine | cut -d ' ' -s -f3)";
BASE_PORT="$(echo $inputLine | cut -d ' ' -s -f4)";
JAVA_HOME_FOR_JBOSS="$(echo $inputLine | cut -d ' ' -s -f5)";
JAVA_HEAP="$(echo $inputLine | cut -d ' ' -s -f6)";
echo "DEPLOYING $APP_SPECIFIC_DEPLOY_SCRIPT"
echo "FROM BRANCH $BRANCH"
echo "IN JBOSS $JBOSS_HOME"
echo "WITH BASE PORT $BASE_PORT"
echo "USING $JAVA_HOME_FOR_JBOSS"
if [[ -n "$JAVA_HEAP" ]]; then
echo "WITH $JAVA_HEAP"
fi
echo
echo "Exporting jboss to $JBOSS_HOME"
ssh me#$SERVER <<END
cleanup() {
rm -f $JBOSS_SERVER/log/*.log
rm -Rf $JBOSS_SERVER/deploy/
rm -Rf $JBOSS_SERVER/tmp/
mkdir $JBOSS_SERVER/deploy
}
startJboss() {
cd $JBOSS_SERVER/bin
./jbossctl.sh start
return 0;
}
export JBOSS_HOME
export JBOSS_SERVER=$JBOSS_HOME/server/default
END
return 0;
}
With that "HERE" approach, I'm getting this error: "syntax error: unexpected end of file"
Thanks a lot in advance!
Just put the functions in your here document, too:
var="Hello World"
ssh user#host <<END
x() {
print "x function with args=$*"
}
x "$var"
END
[EDIT] Some comments:
You say "export JBOSS_HOME" but you never define a value for the variable in the here document. You should use export JBOSS_HOME="$JBOSS_HOME". BASH will take all text between the two END, replace all variables, and send the result to SSH for processing.
That also means the other side will see rm -f /path/to/jboss/server/*.log; the assignment to JBOSS_SERVER in the last line of the here document has no effect (at least not to the code in cleanup()).
If you want to pass $ unmodified to the remote server, you have to escape it with \: rm -f \$JBOSS_SERVER/log/*.log
You never call cleanup()
There is a } missing after return 0 to finish the definition of deployapp()
There may be other problems as well. Run the script with bash -x to see what the shell actually executes. You can also add echo commands in the here document to see what the values of the variables are or you can add set -x before cleanup() to get the same output as with bash -x but from the remote side.
I don't understand why you're using cut to split the arguments to your function. Just do
APP_SPECIFIC_DEPLOY_SCRIPT=$1
BRANCH=$2
JBOSS_HOME=$3
# etc.
If you don't quote your here document delimiter, the contents are expanded before they're sent to the server. That may be what you want. If you don't and you want all expansion to be done on the server side, then quote it like this:
ssh me#$SERVER <<'END'
# etc.
END
If you wan't a mixture, don't quote the delimiter, but do escape those things that you want delayed expansion for:
ssh me#$SERVER <<END
echo $EXPAND_ME_NOW \$EXPAND_ME_LATER
END
What are the export statements supposed to do? I can't see that they would have any effect at all.