[opensuse] BASH - Need help with ssh remote directory test?
Listmates, I have run into another bash caveat I don't understand. Evidently, the ssh call I am making is returning an "exit" following execution of the first pass and never getting to the rest of the hostnames I want to test. It is part of a script that will take a new or modified file and scp it to the same directory on my list of remote hosts. The relevant portions of the script are: FILENAME=`basename $1` if [[ ${DIRNAME:0:1} == '/' ]]; then DIRNAME=`dirname $1` else DIRNAME=${PWD}/`dirname $1` fi while read DESTHOST; do if ssh $DESTHOST '[[ -d "$DIRNAME" || $(mkdir -p "DIRNAME") -eq 0 ]]'; then if scp ${DIRNAME}/${FILENAME} $DESTHOST:${DIRNAME}/${FILENAME}; then echo -e "Transfer to $DESTHOST ${lightgreen}[OK]${nc}" else echo -e "Transfer to $DESTHOST ${red}[Failed]${nc}" fi else echo "$DESTHOST is Unavailable" fi done < /home/david/linux/scripts/network/dsshosts 23:22 alchemy:~> cat /home/david/linux/scripts/network/dsshosts ecstasy killerz nirvana nemesis zion bonza.rbpllc.com providence.rbpllc.com The irrelevant, but curious parts of the script are: red='\e[0;31m' # ${red} lightgreen='\e[1;32m' # ${lightgreen} nc='\e[0m' # ${nc} What happens is the script runs through host ecstasy and then finishes. If I comment the 'if ssh $DESTHOST...' or replace it with anything else, it runs through all the hosts as expected. So for reasons I don't understand, the 'if ssh...' call is making it exit. I have tried every variant I can think of. I tried putting the ssh check in a function: ckdestdir () { return $(ssh $1 '[[ -d "$DIRNAME" || $(mkdir -p "DIRNAME") -eq 0 ]]') } No joy. I tried putting the call in a subshell: if { ssh $DESTHOST '[[ -d "$DIRNAME" || $(mkdir -p "DIRNAME") -eq 0 ]]' }; then No joy, same result every time. It runs through ecstasy and quits. (at least that is consistent). So I'm stumped as to which part of man bash I'm not complying with? Any help to cure my present CRI would be greatly appreciated. -- David C. Rankin, J.D.,P.E. Rankin Law Firm, PLLC 510 Ochiltree Street Nacogdoches, Texas 75961 Telephone: (936) 715-9333 Facsimile: (936) 715-9339 www.rankinlawfirm.com -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Saturday 21 February 2009 00:45:49 David C. Rankin wrote:
I have run into another bash caveat I don't understand. Evidently, the ssh call I am making is returning an "exit" following execution of the first pass and never getting to the rest of the hostnames I want to test. <snipped>
Hi David, Is it possible to 'land' the same script on each host and then 'point' each to the next and have the last one 'point' back to you? regards, Carl -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Fri, 20 Feb 2009, David C. Rankin wrote:-
Listmates,
I have run into another bash caveat I don't understand. Evidently, the ssh call I am making is returning an "exit" following execution of the first pass and never getting to the rest of the hostnames I want to test. It is part of a script that will take a new or modified file and scp it to the same directory on my list of remote hosts. The relevant portions of the script are:
FILENAME=`basename $1` if [[ ${DIRNAME:0:1} == '/' ]]; then DIRNAME=`dirname $1` else DIRNAME=${PWD}/`dirname $1` fi
while read DESTHOST; do if ssh $DESTHOST '[[ -d "$DIRNAME" || $(mkdir -p "DIRNAME") -eq 0 ]]'; then
You're missing a '$' from the front of DIRNAME. You can take the mkdir out of the test as well. Just test for the directory and, if it's not present do the mkdir. If either the check for the directory or the mkdir is successful, the ssh will return '0'. Also, one thing that's very likely to be breaking it is that you've wrapped the string in single quotes, $DIRNAME is passed to the shell on $DESTHOST as is, which means that the test and mkdir will fail because $DIRNAME will be an empty variable. That is unless it is defined on $DESTHOST as a part of the environment.
if scp ${DIRNAME}/${FILENAME} $DESTHOST:${DIRNAME}/${FILENAME}; then
Purely out of curiosity, why are you using scp rather than rsync?
echo -e "Transfer to $DESTHOST ${lightgreen}[OK]${nc}" else echo -e "Transfer to $DESTHOST ${red}[Failed]${nc}" fi else echo "$DESTHOST is Unavailable" fi done < /home/david/linux/scripts/network/dsshosts
Okay. I did a rewrite and this does what you appear to want to do: davjam@playing:~> cat testscript ; ls -l temp/testscript ; bash ./testscript temp/testscript #!/bin/bash #set -x # should be a check in case no arguments passed # [ "$#" -eq 0 ] && exit red='\e[0;31m' # ${red} lightgreen='\e[1;32m' # ${lightgreen} nc='\e[0m' # ${nc} FILENAME=$(basename $1) if [ "${DIRNAME::1}" == '/' ] then DIRNAME=$(dirname $1) else DIRNAME=${PWD}/$(dirname $1) fi TESTSTRING="[ -d \"$DIRNAME\" ] || mkdir -p \"$DIRNAME\"" for DESTHOST in $(<${HOME}/testhosts) do if ssh $DESTHOST "$TESTSTRING" then rsync -aP ${DIRNAME}/${FILENAME} $DESTHOST:${DIRNAME}/ &>/dev/null if [ "$?" -eq 0 ] then echo -e "Transfer to $DESTHOST ${lightgreen}[OK]${nc}" else echo -e "Transfer to $DESTHOST ${red}[Failed]${nc}" fi else echo "$DESTHOST is Unavailable" fi done -rw-r--r-- 1 davjam users 733 2009-02-21 10:08 temp/testscript Transfer to adder.davjam.org [OK] Transfer to thargon.davjam.org [OK] Transfer to lion.davjam.org [OK] Transfer to cobra-mk3.davjam.org [OK] Regards, David Bolt -- Team Acorn: http://www.distributed.net/ OGR-NG @ ~100Mnodes RC5-72 @ ~1Mkeys/s | openSUSE 10.3 32b | openSUSE 11.0 32b | openSUSE 10.2 64b | openSUSE 10.3 64b | openSUSE 11.0 64b | openSUSE 11.1 64b TOS 4.02 | openSUSE 10.3 PPC | RISC OS 3.6 | RISC OS 3.11 -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
David Bolt wrote:
while read DESTHOST; do if ssh $DESTHOST '[[ -d "$DIRNAME" || $(mkdir -p "DIRNAME") -eq 0 ]]'; then
You're missing a '$' from the front of DIRNAME. You can take the mkdir out of the test as well. Just test for the directory and, if it's not present do the mkdir. If either the check for the directory or the mkdir is successful, the ssh will return '0'.
I shouldn't code after midnight ;-)
Also, one thing that's very likely to be breaking it is that you've wrapped the string in single quotes, $DIRNAME is passed to the shell on $DESTHOST as is, which means that the test and mkdir will fail because $DIRNAME will be an empty variable. That is unless it is defined on $DESTHOST as a part of the environment.
That hit the nail on the head! I caught that after Pit's comments, and could have shot myself.
if scp ${DIRNAME}/${FILENAME} $DESTHOST:${DIRNAME}/${FILENAME}; then
Purely out of curiosity, why are you using scp rather than rsync?
No reason. I use rsync for just about everything else and scp was already in my old script I started modifying last night.
Okay. I did a rewrite and this does what you appear to want to do:
davjam@playing:~> cat testscript ; ls -l temp/testscript ; bash ./testscript temp/testscript #!/bin/bash
#set -x
# should be a check in case no arguments passed # [ "$#" -eq 0 ] && exit
red='\e[0;31m' # ${red} lightgreen='\e[1;32m' # ${lightgreen} nc='\e[0m' # ${nc}
FILENAME=$(basename $1) if [ "${DIRNAME::1}" == '/' ]
Now that's a new trick -- no 0.
then DIRNAME=$(dirname $1) else DIRNAME=${PWD}/$(dirname $1) fi
TESTSTRING="[ -d \"$DIRNAME\" ] || mkdir -p \"$DIRNAME\""
for DESTHOST in $(<${HOME}/testhosts)
Also a new trick, Thanks!
do if ssh $DESTHOST "$TESTSTRING" then rsync -aP ${DIRNAME}/${FILENAME} $DESTHOST:${DIRNAME}/ &>/dev/null if [ "$?" -eq 0 ] then echo -e "Transfer to $DESTHOST ${lightgreen}[OK]${nc}" else echo -e "Transfer to $DESTHOST ${red}[Failed]${nc}" fi else echo "$DESTHOST is Unavailable" fi done -rw-r--r-- 1 davjam users 733 2009-02-21 10:08 temp/testscript Transfer to adder.davjam.org [OK] Transfer to thargon.davjam.org [OK] Transfer to lion.davjam.org [OK] Transfer to cobra-mk3.davjam.org [OK]
Regards, David Bolt
David, thank you! The veil of fog has been lifted. The key was TESTSTRING to expand $DIRNAME before making the ssh call. That's what had me wrapped around the axle. Good to be with you. -- David C. Rankin, J.D.,P.E. Rankin Law Firm, PLLC 510 Ochiltree Street Nacogdoches, Texas 75961 Telephone: (936) 715-9333 Facsimile: (936) 715-9339 www.rankinlawfirm.com -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
On Saturday February 21 2009, David C. Rankin wrote:
...
No reason. I use rsync for just about everything else and scp was already in my old script I started modifying last night.
Copy-and-modify... Can't live with it, can't live without it. No matter how many times it bites me, I just keep on doing it.
...
-- David C. Rankin
Randall Schulz -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
Hello, On Sat, 21 Feb 2009, David Bolt wrote:
On Fri, 20 Feb 2009, David C. Rankin wrote:- [..]
while read DESTHOST; do if ssh $DESTHOST '[[ -d "$DIRNAME" || $(mkdir -p "DIRNAME") -eq 0 ]]'; then [..] Also, one thing that's very likely to be breaking it is that you've wrapped the string in single quotes, $DIRNAME is passed to the shell on $DESTHOST as is, which means that the test and mkdir will fail because $DIRNAME will be an empty variable. That is unless it is defined on $DESTHOST as a part of the environment.
Correct, (I guess D.C.R. would have seen that himself, eventually), but that was not the real problem ... [..]
for DESTHOST in $(<${HOME}/testhosts) do
... which you coincidentally avoid here. BTW, you should _always_ quote _all_ variables as "good" as you can! If D.C.R. had quoted the command correctly himself, others might have seen that the problem is something else entirely, and you could have suggested the for-loop as an alternative. The real reason why only the first host is tested is, that ssh "sucks" away all stdin so that the read in the while-loop sees only the first host -- the rest disappears in ssh. Example: $ echo -e "localhost\nlocalhost\nlocalhost" | while read host ; do ssh "$host" 'wc -l'; done dh@localhost's password: 2 (which happens also, if the remote program does _not_ read stdin itself, e.g. using '/bin/true' instead of 'wc -l') The solution is to simply tell ssh not to read stdin: $ echo -e "localhost\nlocalhost\nlocalhost" | while read host ; do ssh "$host" 'wc -l' </dev/null; done dh@localhost's password: 0 dh@localhost's password: 0 dh@localhost's password: 0 And openssh ssh has an '-n' switch. $ DIRNAME="/tmp/test10/foo"; $ test -d /tmp/test10/foo && rmdir /tmp/test10/foo $ echo -e "localhost\nlocalhost\nlocalhost" | while read host ; do ssh -n "$host" "test -d '$DIRNAME' || { echo 'creating \"$DIRNAME\"'; mkdir -p '$DIRNAME'; }"; echo "$?" done; dh@localhost's password: creating "/tmp/test10/foo" 0 dh@localhost's password: 0 dh@localhost's password: 0 And you can simplify quoting and add comments by feeding the commands to ssh via stdin (which is not the while-loop stdin): $ echo -e "localhost\nlocalhost\nlocalhost" | while read host ; do ssh "$host" /bin/bash <<EOCMD; ## this is our stdin for ssh->/bin/bash. If you don't use /bin/bash ## or another shell as remote command, the default login-shell is used ## (includes getting /etc/issue). test -d "$DIRNAME" || { echo "creating \"$DIRNAME\""; mkdir -p '$DIRNAME'; } EOCMD echo $?; done dh@localhost's password: creating "/tmp/test10/foo" 0 dh@localhost's password: 0 dh@localhost's password: 0 You could also use this formatting: $ [..] while read host ; do ssh "$host" /bin/bash <<EOCMD; echo $?; done test -d "$DIRNAME" || { ... } EOCMD i.e. put the rest of the loop behind the '<<EOCMD;'. Oh, and you can feed the while-loop with the 'done < filename'. HTH, -dnh -- Most people would say I write code like I've already lost my mind. -- Randal L. Schwartz -- To unsubscribe, e-mail: opensuse+unsubscribe@opensuse.org For additional commands, e-mail: opensuse+help@opensuse.org
participants (5)
-
Carl Hartung
-
David Bolt
-
David C. Rankin
-
David Haller
-
Randall R Schulz