bash to pass array to ssh to another server - bash

In the below bash I am trying to pass the ${array[$i]} to ssh after changing to a specific directory, but ${array[$i]} it is not recognized? The goal is to use the id in ${array[$i]} (there may be more than 1) to further go into that directory. The bash seems to work as expected except for the ${array[$i]} not be passed.
bash
readarray -t array <<< "$(printf '%s\n' $id)"
for ((i=0; i<${#array[#]}; i++ )) ; do
echo "${array[$i]}"
done
sshpass -f file.txt ssh -o strictHostKeyChecking=no -t xxx#xxx "${array[$i]}" 'cd path/to/folder/"$array[$i]" && exec bash -l'
echo ${array[$i]}
maybe?
readarray -t array <<< "$(printf '%s\n' $id)"
for ((i=0; i<${#array[#]}; i++ )) ; do
echo "${array[$i]}"
done
for i in "${array[$i]} ; do
sshpass -f file.txt ssh -o strictHostKeyChecking=no -t xxx#xxx "${array[$i]}" 'cd path/to/folder && exec bash -l'
done
contents of array[$i] ---- array[$i] will be different in number each time but the format will always be the same ----
00-0000-xxx-xxx-xxx
00-0001-yyy-yyy-yyy
desired ssh
cd path/to/folder/00-0000-xxx-xxx-xxx && cp *.txt* /home/location
cd path/to/folder/00-0000-yyy-yyy-yyy && cp *.txt* /home/location

Here, we generate a single remote that runs (cd ... && exec cp) for each array element, with each in a subshell to prevent the cd from having side effects on subsequent elements' commands:
printf -v cmd_q '(cd /path/to/folder/%q && exec cp -- *.txt* /home/location)\n' "${array[#]}"
sshpass -f file.txt ssh -o strictHostKeyChecking=no -t xxx#xxx "$cmd_q"
The exec is a minor performance enhancement, consuming the subshell started with the parenthesis by replacing it with the cp process.
The %q placeholder in the printf format string gets substituted with the individual array values.

Related

How to assign a color to a variable within a bash function

I have following script where i want to to print the command Variable SMB into the RED colour within a bash function but that's not working.
Below is the Script:
Script:
#!/bin/bash
read -rsp $'Please Enter password below: ' SSHPASS
echo -n ""
export SSHPASS
NC='\033[0m'
RED='\033[0;31m'
remote_connect() {
target_host=$1
sshpass -e ssh -q "${target_host}" "true" -o StrictHostKeyChecking=no -o ConnectTimeout=60 2>>/dev/null
if [[ $? -eq 0 ]]
then
SMB=$(sshpass -e ssh -q -t "$target_host" "sudo smbstatus |grep ^Samba")
printf "%-35s %15s\n" "$target_host" "${RED}${SMB}${NC}"
else
printf "%-35s %15s\n" "$target_host" "Unable to get the ssh connection"
fi
} 2>/dev/null
export -f remote_connect
< host_list xargs -P5 -n1 -d'\n' bash -c 'remote_connect "$#"' --
Result:
tdi1990.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
tdi1856.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
tdi1993.colx.fox.com \033[0;31m Samba version 4.9.1 \033[0m \n
If i use echo like below it works, but then the lifet and right justify as i am trying with print that's not possible with echo.
echo -e "$target_host" "${RED}${SMB}${NC}"
Expected:
Second column that is Samba version 4.9.1 should be printed in Red color.
This should achieve what you expected :
NC=$'\033[0m'
RED=$'\033[0;31m'

How to extract code into a funciton when using xargs -P?

At fisrt,I have write the code,and it run well.
# version1
all_num=10
thread_num=5
a=$(date +%H%M%S)
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c 'echo abc{}'
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
Now I want to extract code into a funciton,but it was wrong,how to fix it?
get_file(i){
echo "abc"+i
}
all_num=10
thread_num=5
a=$(date +%H%M%S)
seq 1 ${all_num} | xargs -n 1 -I {} -P ${thread_num} sh -c "$(get_file {})"
b=$(date +%H%M%S)
echo -e "startTime:\t$a"
echo -e "endTime:\t$b"
Because /bin/sh isn't guaranteed to have support for either printing text that when evaluates defines your function, or exporting functions through the environment, we need to do this the hard way, just duplicating the text of the function inside the copy of sh started by xargs.
Other questions already exist in this site describing how to accomplish this with bash, which is quite considerably easier. See f/e How can I use xargs to run a function in a command substitution for each match?
#!/bin/sh
all_num=10
thread_num=5
batch_size=1 # but with a larger all_num, turn this up to start fewer copies of sh
a=$(date +%H%M%S) # warning: this is really inefficient
seq 1 ${all_num} | xargs -n "${batch_size}" -P "${thread_num}" sh -c '
get_file() { i=$1; echo "abc ${i}"; }
for arg do
get_file "$arg"
done
' _
b=$(date +%H%M%S)
printf 'startTime:\t%s\n' "$a"
printf 'endTime:\t%s\n' "$b"
Note:
echo -e is not guaranteed to work with /bin/sh. Moreover, for a shell to be truly compliant, echo -e is required to write -e to its output. See Why is printf better than echo? on UNIX & Linux Stack Exchange, and the APPLICATION USAGE section of the POSIX echo specification.
Putting {} in a sh -c '...{}...' position is a Really Bad Idea. Consider the case where you're passed in a filename that contains $(rm -rf ~)'$(rm -rf ~)' -- it can't be safely inserted in an unquoted context, or a double-quoted context, or a single-quoted context, or a heredoc.
Note that seq is also nonstandard and not guaranteed to be present on all POSIX-compliant systems. i=0; while [ "$i" -lt "$all_num" ]; do echo "$i"; i=$((i + 1)); done is an alternative that will work on all POSIX systems.

How to make runuser correctly forward all command line arguments, instead of trying to interpret them?

I got this simple script:
#!/bin/bash
SOURCE_USER=$USER
DESTINE_USER=$1
id -u $SOURCE_USER > /dev/null 2>&1
if [ "$?" == "1" ] || [ -z $SOURCE_USER ]
then
printf "Error: Invalid source user '$SOURCE_USER'\\n"
exit 1
fi
if [ -z $DESTINE_USER ]
then
printf "Error: Invalid destine user '$DESTINE_USER'\\n"
exit 1
fi
SOURCE_GROUPS=$(id -Gn ${SOURCE_USER} | sed "s/${SOURCE_USER} //g" | sed "s/ ${SOURCE_USER}//g" | sed "s/ /,/g")
SOURCE_SHELL=$(awk -F : -v name=${SOURCE_USER} '(name == $1) { print $7 }' /etc/passwd)
id -u $DESTINE_USER > /dev/null 2>&1
if [ "$?" == "1" ]
then
printf "Creating destine user %s\\n" "$DESTINE_USER"
useradd --groups ${SOURCE_GROUPS} --shell ${SOURCE_SHELL} --create-home ${DESTINE_USER}
passwd ${DESTINE_USER}
xhost '+si:localuser:$DESTINE_USER'
sudo usermod -G "$SOURCE_USER" "$DESTINE_USER"
else
printf "Updating destine user '%s' with groups '%s' and shell '%s'\\n" "$DESTINE_USER" "$SOURCE_GROUPS" "$SOURCE_SHELL"
sudo usermod -a -G "$SOURCE_GROUPS" "$DESTINE_USER"
sudo chsh -s "$SOURCE_SHELL" "$SOURCE_USER"
fi
sudo runuser sublime_vanilla -c "${#:2}"
I run it like this:
$ bash run_as_user.sh sublime_vanilla /usr/bin/subl -n "./New Empty File"
But when I run it, I got this error:
runuser: invalid option -- 'n'
Try 'runuser --help' for more information.
But if I replace sudo runuser sublime_vanilla -c "${#:2}" with sudo runuser sublime_vanilla -c "\"$2\" \"$3\" \"$4\" \"$5\" \"$6\" \"$7\" \"$8\" \"${#:9}\""
Then, Sublime Text correctly opens the file "./New Empty File" in a new window.
How to make runuser correctly understand all argument with a variable number of command line arguments, i.e., without hard coding "\"$2\" \"$3\" \"$4\" ..."?
This is slightly different from your last question because you have to make the expansion of the arguments into a single string for the -c option.
The bash printf formatter %q is your friend here:
cmd=$( printf '%q ' "${#:2}" )
sudo runuser sublime_vanilla -c "$cmd"
On the other hand, a quick perusal through the runuser man page suggests:
sudo runuser -u sublime_vanilla "${#:2}"
Another thought: sudo runuser -u sublime_vanilla -- "${#:2}" with the double hyphens to indicate the end of the runuser options.

Passing -e and -n as positional parameters in Bash

I've recently been working with positional parameters in some bash scripts and I've noticed that -e and -n do not appear to be passed as positional parameters. I've been searching through documentation but haven't been able to figure out why. Consider the following short scripts:
#!/bin/bash
# test.sh
echo $#
echo $1
echo $2
echo $3
echo $4
echo $5
exit
Running the command: # ./test.sh -e -f -c -n -g outputs:
-f -c -n -g
-f
-c
-g
./test.sh -n -f -c -e -g outputs:
-f -c -e -g-f
-c
-g
Why do -e and -n not appear in "$#"? -e appears to pass as an empty parameter and -n appears to remove the following endline. Furthermore I noticed that these parameters are accounted for when echoing $#. Does anyone know why -e and -n behave differently than any other parameters.
The -e is passed like an argument to echo and then is comsumed by it.
Try this instead :
#!/bin/bash
printf '%s\n' "$1"
printf '%s\n' "$2"
printf '%s\n' "$3"
printf '%s\n' "$4"
printf '%s\n' "$5"
Output :
-e
-f
-c
-n
-g
Check help echo | less +/-e
You can use :
echo -- "$1"
too
Another solution
using bash here document
#!/bin/bash
cat<<EOF
$1
$2
$3
$4
$5
EOF

bsub post processing script

I was writing a script for submitting parallel jobs in cluster using bsub command
while read p; do
cd $(echo $p | tr -d '\r')
echo Submitting test: $p
bsub -P <project> -Jd <job desc> -o lsf.log "sh ./run_test.sh &> $log"
cd - &> /dev/null
done < $filename
How can I compile the results at the end of all test runs?
How about using something like this?
while read p; do
cd "$(echo "$p" | tr -d '\r')"
echo "Submitting test: $p"
bsub -P <project> -Jd <job desc> -o lsf.log \
"sh ./run_test.sh &> '$log' && cat '$log' >> /path/to/combined/log"
cd - &> /dev/null
done < "$filename"
When each job finishes successfully, the output file is concatenated with the rest.

Resources