How can I adb install an apk to multiple connected devices? - java

I have 7 devices plugged into my development machine.
Normally I do adb install <path to apk> and can install to just a single device.
Now I would like to install my apk on all of my 7 connected devices. How can I do this in a single command? I'd like to run a script perhaps.

You can use adb devices to get a list of connected devices and then run adb -s DEVICE_SERIAL_NUM install... for every device listed.
Something like (bash):
adb devices | tail -n +3 | cut -sf 1 -d " " | xargs -iX adb -s X install ...
Comments suggest this might work better for newer versions:
adb devices | tail -n +2 | cut -sf 1 | xargs -iX adb -s X install ...
For Mac OSX(not tested on Linux):
adb devices | tail -n +2 | cut -sf 1 | xargs -I {} adb -s {} install ...

The other answers were very useful however didn't quite do what I needed. I thought I'd post my solution (a shell script) in case it provides more clarity for other readers. It installs multiple apks and any mp4s
echo "Installatron"
for SERIAL in $(adb devices | tail -n +2 | cut -sf 1);
do
for APKLIST in $(ls *.apk);
do
echo "Installatroning $APKLIST on $SERIAL"
adb -s $SERIAL install $APKLIST
done
for MP4LIST in $(ls *.mp4);
do
echo "Installatroning $MP4LIST to $SERIAL"
adb -s $SERIAL push $MP4LIST sdcard/
done
done
echo "Installatron has left the building"
Thank you for all the other answers that got me to this point.

Here's a functional one line command tailored from kichik's response (thanks!):
adb devices | tail -n +2 | cut -sf 1 | xargs -iX adb -s X install -r *.apk
But if you happen to be using Maven it's even simpler:
mvn android:deploy

Another short option... I stumbled on this page to learn that the -s $SERIAL has to come before the actual adb command! Thanks stackoverflow!
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do `adb -s $SERIAL install -r /path/to/product.apk`;
done

Generalized solution from Dave Owens to run any command on all devices:
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do echo adb -s $SERIAL $#;
done
Put it in some script like "adb_all" and use same way as adb for single device.
Another good thing i've found is to fork background processes for each command, and wait for their completion:
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do adb -s $SERIAL $# &
done
for job in `jobs -p`
do wait $job
done
Then you can easily create a script to install app and start the activity
./adb_all_fork install myApp.apk
./adb_all_fork shell am start -a android.intent.action.MAIN -n my.package.app/.MainActivity

I liked workingMatt's script but thought it could be improved a bit, here's my modified version:
#!/bin/bash
install_to_device(){
local prettyName=$(adb -s $1 shell getprop ro.product.model)
echo "Starting Installatroning on $prettyName"
for APKLIST in $(find . -name "*.apk" -not -name "*unaligned*");
do
echo "Installatroning $APKLIST on $prettyName"
adb -s $1 install -r $APKLIST
adb -s $1 shell am start -n com.foo.barr/.FirstActivity;
adb -s $1 shell input keyevent KEYCODE_WAKEUP
done
echo "Finished Installatroning on $prettyName"
}
echo "Installatron"
gradlew assembleProdDebug
for SERIAL in $(adb devices | tail -n +2 | cut -sf 1);
do
install_to_device $SERIAL&
done
My version does the same thing except:
it finds the apks from the root of the project
it installs to every device simultaneously
it excludes the "unaligned" versions of the apks (these were just being installed over by the aligned versions anyway
it shows the readable names for the phones instead if their device ids
There's a few ways it could still be improved but I'm quite happy with it.

The following command should work:
$ adb devices | tail -n +2 | head -n -1 | cut -f 1 | xargs -I X adb -s X install -r path/to/your/package.apk
adb devices returns the list of devices. Use tail -n +2 to start from the 2nd line and head -n -1 to remove the last blank line at the end. Piping through cut with the default tab delimiter gets us the first column which are the serials.
xargs is used to run the adb command for each serial. Remove the -r option if you are not re-installing.

With this script you can just do:
adb+ install <path to apk>
Clean, simple.

If you don't want use the devices that have not enabled adb; use this
Mac/Linux
adb devices | grep device | grep -v devices | awk '{print$1}' | xargs -I {} adb -s {} install path/to/yourApp.apk
adb devices | grep device | grep -v devices | cut -sf 1 | xargs -I {} adb -s {} install path/to/yourApp.apk

Use this command-line utility: adb-foreach

PowerShell solution
function global:adba() {
$deviceIds = iex "adb devices" | select -skip 1 | %{$_.Split([char]0x9)[0].Trim() } | where {$_ -ne "" }
foreach ($deviceId in $deviceIds) {
Echo ("--Executing on device " + $deviceId + ":---")
iex ("adb -s $deviceId " + $args)
}
}
Put this in your profile file (notepad $PROFILE), restart your shell and you can invoke installations with :
adba install yourApp.apk

This command works perfect
adb devices | awk 'NR>1{print $1}' | xargs -n1 -I% adb -s % install foo.apk

well its simple you can create a installapk.bat file that can do the job for multiple apk to multiple connected devices open installapk.bat with notepad++ and copy paste this code
FOR /F "skip=1" %%x IN ('adb devices') DO start adb -s %%x install -r Facebook.apk
FOR /F "skip=1" %%x IN ('adb devices') DO start adb -s %%x install -r Instagram.apk
FOR /F "skip=1" %%x IN ('adb devices') DO start adb -s %%x install -r Messenger.apk
FOR /F "skip=1" %%x IN ('adb devices') DO start adb -s %%x install -r Outlook.apk
FOR /F "skip=1" %%x IN ('adb devices') DO start adb -s %%x install -r Viber.apk
FOR /F "skip=1" %%x IN ('adb devices') DO start adb -s %%x install -r WhatsApp.apk

Here is bash for install and run apk on all connected devices
Using
nick#nickolay:/home/workspace/MyProject$ > bash path/to/installAndRunApk.sh
installAndRunApk.sh
#!/usr/bin/env bash
#--------find apk---------
apkFile=$(find -name '*.apk' -print | grep -oP '(?<=.).*(.apk)')
#--------find apkFilePath---------
if test -z "apkFile"
then
echo "apkFile: is NULL"
exit 0;
fi
echo "apkFile: ${apkFile}"
apkFilePath=$(pwd)${apkFile}
echo "apk file path: ${apkFilePath}"
#--------install---------
if test -z "$apkFilePath"
then
echo "apkFilePath: is NULL"
exit 0;
fi
echo "adb install -t -r ${apkFilePath}"
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do `adb -s ${SERIAL} install -t -r ${apkFilePath}`;
done
#--------get applicationId---------
echo "aapt dump badging ${apkFilePath} | grep -oP '(?<=package: name=).*(?=versionCode)'"
applicationId=$(aapt dump badging ${apkFilePath} | grep -oP '(?<=package: name=).*(?=versionCode)')
echo "applicationId: is ${applicationId}"
#--------launch---------
if test -z "$applicationId"
then
echo "applicationId: is NULL"
exit 0;
fi
echo "____________________START_APPLICATION_ID________________________"
echo "applicationId: ${applicationId}"
echo "____________________END_APPLICATION_ID__________________________"
echo "____________________START_LAUNCHER______________________________"
for SERIAL in $(adb devices | grep -v List | cut -f 1);
do `adb -s ${SERIAL} shell monkey -p ${applicationId} -c android.intent.category.LAUNCHER 1`;
done
echo "____________________END_LAUNCHER________________________________"

I added to the answer from #WorkingMatt
I updated his answer to additionally do the following things
Attempt to connect to all devices on the local network with open port 5555. Warning: this may be a security risk. Beware connecting to arbitrary ports unless you know that it is safe. I am not trained in cybersecurity, so take my advice here with a grain of salt.
Uninstall the previous version of the package if there is one installed (In my case I am uninstalling to remove previous app data)
#!/bin/bash
echo "Installatron2"
# Connect to all devices on the local network (in our case 192.168.0.0)
# This section requires nmap (You may need sudo apt install nmap)
echo "Scanning the network for connected debuggable devices"
ADDRESSES=$(nmap --open -p 5555 192.168.0/24 -oG - | grep "/open" | awk '{ print $2 }')
for ADDRESS in $ADDRESSES;
do
adb connect $ADDRESS
done
# Print devices connected to
echo "Connected to the following devices"
echo "$(adb devices)"
# Iterate through all apks in current directory
for SERIAL in $(adb devices | tail -n +2 | cut -sf 1);
do
for APKLIST in $(ls *.apk);
do
#Get the package name from the apk file (Needs sudo apt install aapt)
package=$(aapt dump badging "$APKLIST" | awk '/package/{gsub("name=|'"'"'",""); print $2}')
# Optionally uninstalls the pre-existing version of this package (In case you do not want to retain data)
echo "Uninstalling $package on $SERIAL"
adb uninstall $package
# Now install with replacement to the same device
echo "Installatroning $APKLIST on $SERIAL"
adb -s $SERIAL install -r $APKLIST
done
done
echo "Installatron2 has left the building"

With Android Debug Bridge version 1.0.29, try this bash script:
APK=$1
if [ ! -f `which adb` ]; then
echo 'You need to install the Android SDK before running this script.';
exit;
fi
if [ ! $APK ]; then
echo 'Please provide an .apk file to install.'
else
for d in `adb devices | ack -o '^\S+\t'`; do
adb -s $d install $APK;
done
fi
Not sure if it works with earlier versions.

The key is to launch adb in a separate process (&).
I came up with the following script to simultaneously fire-off installation on all of the connected devices of mine and finally launch installed application on each of them:
#!/bin/sh
function install_job {
adb -s ${x[0]} install -r PATH_TO_YOUR_APK
adb -s ${x[0]} shell am start -n "com.example.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER
}
#iterate over devices IP-addresses or serial numbers and start a job
while read LINE
do
eval x=($LINE)
install_job ${x[0]} > /dev/null 2>&1 &
done <<< "`adb devices | cut -sf 1`"
echo "WATING FOR INSTALLATION PROCESSES TO COMPLETE"
wait
echo "DONE INSTALLING"
Note 1: the STDOUT and STDERR are suppressed. You won't see any "adb install" operation result. This may be improved, I guess, if you really have to
Note 2: you could also improve script by providing args instead of hardcoded path and activity names.
That way you:
Don't have to manually perform install on each device
Don't have to wait for one install to finish in order to execute another one (adb tasks are launched in parallel)

Originated from here: Make The Previous Post A Mass APK Installer That Does Not Uses ADB Install-Multi Syntax
#echo off
:loop
::-------------------------- has argument ?
if ["%~1"]==[""] (
echo done.
goto end
)
::-------------------------- argument exist ?
if not exist %~s1 (
echo error "%~1" does not exist in file-system.
) else (
echo "%~1" exist
if exist %~s1\NUL (
echo "%~1" is a directory
) else (
echo "%~1" is a file! - time to install:
call adb install %~s1
)
)
::--------------------------
shift
goto loop
:end
pause
::: ##########################################################################
::: ## ##
::: ## 0. run: adb devices - to start the deamon and list your device ##
::: ## ##
::: ## 1. drag&drop ANY amount of files (APK) over this batch files, ##
::: ## ##
::: ## - it will install them one by one. ##
::: ## - it just checks if file exists. ##
::: ## - it does not checks if it is a valid APK package ##
::: ## - it does not checks if package-already-installed ##
::: ## - if there is an error you can always press [CTRL]+[C] ##
::: ## to stop the script, and continue from the next one, ##
::: ## some other time. ##
::: ## - the file is copied as DOS's 8.3 naming to you ##
::: ## don't need to worry about wrapping file names or renaming ##
::: ## them, just drag&drop them over this batch. ##
::: ## ##
::: ## Elad Karako 1/1/2016 ##
::: ## http://icompile.eladkarako.com ##
::: ##########################################################################

Since I can't comment on the answer by #Tom, this worked for me on OSX 10.13
adb devices | tail -n +2 | cut -sf 1 | xargs -IX adb -s X install -r path/to/apk.apk
(Change the little i to a big I)

I was wanting to log what was happening whilst installing, also needed it to be slightly comprehendable. Ended up with:
echo "Installing app on all connected devices."
adb devices | tail -n +2 | cut -sf 1 | xargs -I % sh -c '{ \
echo "Installing on %"; \
adb -s % \
install myApp.apk; \
; }'
Tested on Linux & Mac

-Get all the apk stored in .apk folder
-Install and replace app on devices
getBuild() {
for entry in .apk/*
do
echo "$entry"
done
return "$entry"
}
newBuild="$(getBuild)"
adb devices | while read line
do
if [! "$line" = ""] && ['echo $line | awk "{print $2}"' = "device"]
then
device='echo $line | awk "{print $1}"'
echo "adb -s $device install -r $newbuild"
adb -s $device install -r $newbuild
fi
done

Related

Runtime.getRuntime().exec(command) - Cannot run program, error=2, No such file or directory

I want to get video duration with help of ffmpeg:
String command = "ffmpeg -i /home/user/Videos/my-video.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,"
Runtime.getRuntime().exec(cmdarray);
But i always get
java.io.IOException: Cannot run program "ffmpeg -i /home/user/Videos/my-video.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,": error=2, No such file or directory
If I run this command from terminal - all is ok
You've got several issues here. Firstly as #joy points out there could be a problem with the Path used by Java to locate the command so Java may not be finding a command called "ffmpeg". Fixing the Path used for launching your VM should resolve that, or just insert the fully qualified pathname to "ffmpeg".
Secondly: you are trying to run a terminal / shell command. The "|" pipes are normally interpretted correctly by a terminal / shell which breaks the chain into sub-processes linking stdout/stdin. But Java is being asked to run "ffmpeg" passing in some arguments containing "|" which would not be handled as you wish by "ffmpeg".
Check the shell you use:
echo $SHELL
Let's say that printed /bin/bash - you can fix by getting Java to launch the shell and make that interpret the pipe command:
String[] command = new String[] { "/bin/bash", "-c", "ffmpeg -i /home/user/Videos/my-video.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ," };
Runtime.getRuntime().exec(cmdarray);
Most likely the path isn't the same when you run from terminal vs when you run from Java. 1. you can try using the full path of ffmpeg (run "which ffmpeg" in terminal). 2. perhaps ffmpeg is an alias in your .profile file in that case you can try to source(load) your .profile file first before executing the command in Java.

Check and run/restart processes, bash [duplicate]

This question already has answers here:
Linux Script to check if process is running and act on the result
(8 answers)
Closed 5 years ago.
I wrote a bash-script to check if a process is running. It doesn't work since the ps command always returns exit code 1. When I run the ps command from the command-line, the $? is correctly set, but within the script it is always 1. Any idea?
#!/bin/bash
SERVICE=$1
ps -a | grep -v grep | grep $1 > /dev/null
result=$?
echo "exit code: ${result}"
if [ "${result}" -eq "0" ] ; then
echo "`date`: $SERVICE service running, everything is fine"
else
echo "`date`: $SERVICE is not running"
fi
Bash version: GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
There are a few really simple methods:
pgrep procname && echo Running
pgrep procname || echo Not running
killall -q -0 procname && echo Running
pidof procname && echo Running
This trick works for me. Hope this could help you. Let's save the followings as checkRunningProcess.sh
#!/bin/bash
ps_out=`ps -ef | grep $1 | grep -v 'grep' | grep -v $0`
result=$(echo $ps_out | grep "$1")
if [[ "$result" != "" ]];then
echo "Running"
else
echo "Not Running"
fi
Make the checkRunningProcess.sh executable.And then use it.
Example to use.
20:10 $ checkRunningProcess.sh proxy.py
Running
20:12 $ checkRunningProcess.sh abcdef
Not Running
I tried your version on BASH version 3.2.29, worked fine. However, you could do something like the above suggested, an example here:
#!/bin/sh
SERVICE="$1"
RESULT=`ps -ef | grep $1 | grep -v 'grep' | grep -v $0`
result=$(echo $ps_out | grep "$1")
if [[ "$result" != "" ]];then
echo "Running"
else
echo "Not Running"
fi
I use this one to check every 10 seconds process is running and start if not and allows multiple arguments:
#!/bin/sh
PROCESS="$1"
PROCANDARGS=$*
while :
do
RESULT=`pgrep ${PROCESS}`
if [ "${RESULT:-null}" = null ]; then
echo "${PROCESS} not running, starting "$PROCANDARGS
$PROCANDARGS &
else
echo "running"
fi
sleep 10
done
Check if your scripts name doesn't contain $SERVICE. If it does, it will be shown in ps results, causing script to always think that service is running. You can grep it against current filename like this:
#!/bin/sh
SERVICE=$1
if ps ax | grep -v grep | grep -v $0 | grep $SERVICE > /dev/null
then
echo "$SERVICE service running, everything is fine"
else
echo "$SERVICE is not running"
fi
Working one.
!/bin/bash
CHECK=$0
SERVICE=$1
DATE=`date`
OUTPUT=$(ps aux | grep -v grep | grep -v $CHECK |grep $1)
echo $OUTPUT
if [ "${#OUTPUT}" -gt 0 ] ;
then echo "$DATE: $SERVICE service running, everything is fine"
else echo "$DATE: $SERVICE is not running"
fi
Despite some success with the /dev/null approach in bash. When I pushed the solution to cron it failed. Checking the size of a returned command worked perfectly though. The ampersrand allows bash to exit.
#!/bin/bash
SERVICE=/path/to/my/service
result=$(ps ax|grep -v grep|grep $SERVICE)
echo ${#result}
if ${#result}> 0
then
echo " Working!"
else
echo "Not Working.....Restarting"
/usr/bin/xvfb-run -a /opt/python27/bin/python2.7 SERVICE &
fi
#!/bin/bash
ps axho comm| grep $1 > /dev/null
result=$?
echo "exit code: ${result}"
if [ "${result}" -eq "0" ] ; then
echo "`date`: $SERVICE service running, everything is fine"
else
echo "`date`: $SERVICE is not running"
/etc/init.d/$1 restart
fi
Something like this
Those are helpful hints. I just needed to know if a service was running when I started the script, so I could leave the service in the same state when I left. I ended up using this:
HTTPDSERVICE=$(ps -A | grep httpd | head -1)
[ -z "$HTTPDSERVICE" ] && echo "No apache service running."
I found the problem. ps -ae instead ps -a works.
I guess it has to do with my rights in the shared hosting environment. There's apparently a difference between executing "ps -a" from the command line and executing it from within a bash-script.
A simple script version of one of Andor's above suggestions:
!/bin/bash
pgrep $1 && echo Running
If the above script is called test.sh then, in order to test, type:
test.sh NameOfProcessToCheck
e.g.
test.sh php
I was wondering if it would be a good idea to have progressive attempts at a process, so you pass this func a process name func_terminate_process "firefox" and it tires things more nicely first, then moves on to kill.
# -- NICE: try to use killall to stop process(s)
killall ${1} > /dev/null 2>&1 ;sleep 10
# -- if we do not see the process, just end the function
pgrep ${1} > /dev/null 2>&1 || return
# -- UGLY: Step trough every pid and use kill -9 on them individually
for PID in $(pidof ${1}) ;do
echo "Terminating Process: [${1}], PID [${PID}]"
kill -9 ${PID} ;sleep 10
# -- NASTY: If kill -9 fails, try SIGTERM on PID
if ps -p ${PID} > /dev/null ;then
echo "${PID} is still running, forcefully terminating with SIGTERM"
kill -SIGTERM ${PID} ;sleep 10
fi
done
# -- If after all that, we still see the process, report that to the screen.
pgrep ${1} > /dev/null 2>&1 && echo "Error, unable to terminate all or any of [${1}]" || echo "Terminate process [${1}] : SUCCESSFUL"
I need to do this from time to time and end up hacking the command line until it works.
For example, here I want to see if I have any SSH connections, (the 8th column returned by "ps" is the running "path-to-procname" and is filtered by "awk":
ps | awk -e '{ print $8 }' | grep ssh | sed -e 's/.*\///g'
Then I put it in a shell-script, ("eval"-ing the command line inside of backticks), like this:
#!/bin/bash
VNC_STRING=`ps | awk -e '{ print $8 }' | grep vnc | sed -e 's/.*\///g'`
if [ ! -z "$VNC_STRING" ]; then
echo "The VNC STRING is not empty, therefore your process is running."
fi
The "sed" part trims the path to the exact token and might not be necessary for your needs.
Here's my example I used to get your answer. I wrote it to automatically create 2 SSH tunnels and launch a VNC client for each.
I run it from my Cygwin shell to do admin to my backend from my windows workstation, so I can jump to UNIX/LINUX-land with one command, (this also assumes the client rsa keys have already been "ssh-copy-id"-ed and are known to the remote host).
It's idempotent in that each proc/command only fires when their $VAR eval's to an empty string.
It appends " | wc -l" to store the number of running procs that match, (i.e., number of lines found), instead of proc-name for each $VAR to suit my needs. I keep the "echo" statements so I can re-run and diagnose the state of both connections.
#!/bin/bash
SSH_COUNT=`eval ps | awk -e '{ print $8 }' | grep ssh | sed -e 's/.*\///g' | wc -l`
VNC_COUNT=`eval ps | awk -e '{ print $8 }' | grep vnc | sed -e 's/.*\///g' | wc -l`
if [ $SSH_COUNT = "2" ]; then
echo "There are already 2 SSH tunnels."
elif [ $SSH_COUNT = "1" ]; then
echo "There is only 1 SSH tunnel."
elif [ $SSH_COUNT = "0" ]; then
echo "connecting 2 SSH tunnels."
ssh -L 5901:localhost:5901 -f -l USER1 HOST1 sleep 10;
ssh -L 5904:localhost:5904 -f -l USER2 HOST2 sleep 10;
fi
if [ $VNC_COUNT = "2" ]; then
echo "There are already 2 VNC sessions."
elif [ $VNC_COUNT = "1" ]; then
echo "There is only 1 VNC session."
elif [ $VNC_COUNT = "0" ]; then
echo "launching 2 vnc sessions."
vncviewer.exe localhost:1 &
vncviewer.exe localhost:4 &
fi
This is very perl-like to me and possibly more unix utils than true shell scripting. I know there are lots of "MAGIC" numbers and cheezy hard-coded values but it works, (I think I'm also in poor taste for using so much UPPERCASE too). Flexibility can be added with some cmd-line args to make this more versatile but I wanted to share what worked for me. Please improve and share. Cheers.
A solution with service and awk that takes in a comma-delimited list of service names.
First it's probably a good bet you'll need root privileges to do what you want. If you don't need to check then you can remove that part.
#!/usr/bin/env bash
# First parameter is a comma-delimited string of service names i.e. service1,service2,service3
SERVICES=$1
ALL_SERVICES_STARTED=true
if [ $EUID -ne 0 ]; then
if [ "$(id -u)" != "0" ]; then
echo "root privileges are required" 1>&2
exit 1
fi
exit 1
fi
for service in ${SERVICES//,/ }
do
STATUS=$(service ${service} status | awk '{print $2}')
if [ "${STATUS}" != "started" ]; then
echo "${service} not started"
ALL_SERVICES_STARTED=false
fi
done
if ${ALL_SERVICES_STARTED} ; then
echo "All services started"
exit 0
else
echo "Check Failed"
exit 1
fi
The most simple check by process name :
bash -c 'checkproc ssh.exe ; while [ $? -eq 0 ] ; do echo "proc running";sleep 10; checkproc ssh.exe; done'

Have script detect gnome session

I have a makeself script which I expect to be run as root; It's a desktop installer.
At the end of the script, the software which was recently installed to the filesystem tries to launch in user-space.
This works well using sudo -u $(logname) /path/to/application (or alternately sudo -u $SUDO_USER ... in Ubuntu 16.04) however a critical environmental variable from the user is missing:
GNOME_DESKTOP_SESSION_ID
I need GNOME_DESKTOP_SESSION_ID because the child process belongs to Java and Java uses this environmental variable for detecting the GtkLookAndFeel.
However attempts to use sudo -i have failed.
From some basic tests, the GNOME_DESKTOP_SESSION_ID doesn't appear to be a natural environmental variable when this users logs in. For example, if I CTRL+ALT+F1 to a terminal, env |grep GNOME yields nothing whereas XTerm and gnome-terminal both yield GNOME_DESKTOP_SESSION_ID.
How can I get a hold of this GNOME_DESKTOP_SESSION_ID variable from within the installer script without requiring users to pass something such as the -E parameter to the sudo command?
Note, although GtkLookAndFeel is the primary look and feel for Linux, I prefer not to hard-code the export JAVA_OPTS either, I prefer to continue to fallback onto Oracle's detection techniques for support, longevity and scalability reasons.
Update: In Ubuntu, GNOME_DESKTOP_SESSION_ID lives in /usr/share/upstart/sessions/xsession-init.conf
initctl set-env --global GNOME_DESKTOP_SESSION_ID=this-is-deprecated
Which leads to using initctl get-env to retrieve it. Unfortunately this does not help within a new sudo shell, nor does any (optimistic) attempt at dbus-launch.
It turns out this is a two-step process...
Read the user's UPSTART_SESSION environmental variables from /proc/$pid/environ
Then export UPSTART_SESSION and call initctl --user get-env GNOME_DESKTOP_SESSION_ID
To make this a bit more scalable to other variables, I've wrapped this into a bash helper function. This function should assist fetching other user-environment variables as well. Word of caution, it won't work if the variable's value has a space in the name.
In the below example, only UPSTART_SESSION and GNOME_DESKTOP_SESSION_ID are required to answer the question.
Once sudo_env is called, the next call to sudo -u ... must be changed to sudo -E -u .... The -E will import the newly exported variables for use by a child process.
# Provide user environmental variables to the sudo environment
function sudo_env() {
userid="$(logname 2>/dev/null || echo $SUDO_USER)"
pid=$(ps aux |grep "^$userid" |grep "dbus-daemon" | grep "unix:" |awk '{print $2}')
# Replace null delimiters with newline for grep
envt=$(cat "/proc/$pid/environ" |tr '\0' '\n')
# List of environmental variables to use; adjust as needed
# UPSTART_SESSION must come before GNOME_DESKTOP_SESSION_ID
exports=( "UPSTART_SESSION" "DISPLAY" "DBUS_SESSION_BUS_ADDRESS" "XDG_CURRENT_DESKTOP" "GNOME_DESKTOP_SESSION_ID" )
for i in "${exports[#]}"; do
# Re-set the variable within this session by name
# Careful, this technique won't yet work with spaces
if echo "$envt" | grep "^$i=" > /dev/null 2>&1; then
eval "$(echo "$envt" | grep "^$i=")" > /dev/null 2>&1
export $i > /dev/null 2>&1
elif initctl --user get-env $i > /dev/null 2>&1; then
eval "$i=$(initctl --user get-env $i)" > /dev/null 2>&1
export $i > /dev/null 2>&1
fi
echo "$i=${!i}"
done
}
You need to create a new file on /etc/sudoers.d with this content:
Defaults env_keep+=GNOME_DESKTOP_SESSION_ID
But, there is a problem, if you already are inside sudo, it will not been read again.
So, the complete solution is use sudo inside your script to create this file and then execute your command in another sudo:
#!/bin/bash
# ignore sudo
if [[ -z $SUDO_USER ]]; then
#save current dir
DIR="$(pwd)"
#generate random string (file name compatible)
NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
#create env_keep file
sudo -i -- <<EOF0
echo "Defaults env_keep+=GNOME_DESKTOP_SESSION_ID" > /etc/sudoers.d/"$NEW_UUID"_keep_java_laf
EOF0
sudo -u YOUR_USER -i -- <<EOF
#go to original directory
cd "$DIR"
#execute your java command
java YOUR_COMMAND
EOF
#clean file
sudo rm -f /etc/sudoers.d/"$NEW_UUID"_keep_java_laf
else
echo "sudo not allowed!";exit 1;
fi

installing tomcat and java on centos using bash [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
i am having a problem starting the tomcat service properly after installing it. i am using centos 7 bash 4.
if the tomcat user and the tomcat service name are the same my script works fine, and gets the service pid at the end, but if they are different then something goes wrong and the service does not work properly and it does not get service pid.
here are the scripts that i am using.
can anyone tell me what could be the reason for this conflict?
thanks .
deployScript.sh
#!/bin/bash
tomcatDirName="tomcat802"
tomcatSvcName="tomcatSvc"
tomcatSvcUsr="tomcatUsr"
tomcatSvcGrp="tomcatGrp"
installationPath="/opt/app"
javaDirName="java"
javaDirPath="$installationPath/$javaDirName"
jdkDirPath="$javaDirPath/jdk1.8.0_45"
userHomePath="$installationPath/$tomcatSvcUsr"
tomcatDirPath="$installationPath/$tomcatDirName"
tomcatConfPath="$tomcatDirPath/conf"
tomcatLogsPath="$tomcatDirPath/logs"
tomcatBinPath="$tomcatDirPath/bin"
tomcatLogsTomcat="$tomcatLogsPath/tomcat"
tomcatLogsAccess="$tomcatLogsPath/access"
setEnvShPath="$tomcatBinPath/setenv.sh"
catalinaShSearch='CATALINA_OUT="$CATALINA_BASE.*'
catalinaShReplace='CATALINA_OUT="$CATALINA_BASE"/logs/tomcat/catalina.out'
catalinaShPath="$tomcatBinPath/catalina.sh"
initDTomcatFilePath="/etc/init.d/$tomcatSvcName"
catalinaLogsSearch='${catalina.base}/logs'
catalinaLogsReplace='${catalina.base}/logs/tomcat'
loggingPropertiesPath="$tomcatConfPath/logging.properties"
serverXMLPath="$tomcatConfPath/server.xml"
maxPostSize="15728640"
##Download Tomcat
wget http://archive.apache.org/dist/tomcat/tomcat-8/v8.0.21/bin/apache-tomcat-8.0.21.tar.gz
# Download JDK
wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u45-b14/jdk-8u45-linux-x64.tar.gz"
wget http://pkgs.repoforge.org/rpmforge-release/rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm
rpm -ihv rpmforge-release-0.5.3-1.el7.rf.x86_64.rpm
yum -y install epel-release
yum -y install xmlstarlet
yum -y install htop
mkdir -p $tomcatDirPath
mkdir -p $javaDirPath
mkdir -p $userHomePath
tar -xzf jdk-8u45-linux-x64.tar.gz -C $javaDirPath
rm -f $jdkDirPath/javafx-src.zip
rm -f $jdkDirPath/src.zip
tar -xzf apache-tomcat-8.0.21.tar.gz -C $tomcatDirPath --strip-components=1
rm -rf $tomcatDirPath/webapps/docs
rm -rf $tomcatDirPath/webapps/examples
rm -rf $tomcatDirPath/webapps/host-manager
rm -rf $tomcatDirPath/webapps/ROOT/*
# add user and permissions
groupadd $tomcatSvcGrp
useradd -M -s /sbin/nologin -g $tomcatSvcGrp -d $userHomePath $tomcatSvcUsr
findAndReplace() {
declare -A TomcatInitD=(
["^CATALINA_HOME.*"]="CATALINA_HOME=$tomcatDirPath"
#["^TOMCAT_USER.*"]="TOMCAT_USER=$tomcatSvcUsr"
#["^TOMCAT_SVC.*"]="TOMCAT_SVC=$tomcatSvcName"
["^export JAVA_HOME=.*"]="export JAVA_HOME=$jdkDirPath"
)
for i in "${!TomcatInitD[#]}"
do
value="${TomcatInitD[$i]}"
key="$i"
sed -i -e "s~$key~$value~" $initDTomcatFilePath
done
}
cp tomcat801_init.d.txt $initDTomcatFilePath
cp setenv.sh $setEnvShPath
if [ -f $initDTomcatFilePath ]
then
findAndReplace
else
cp tomcat801_init.d.txt $initDTomcatFilePath
findAndReplace
fi
chown $tomcatSvcUsr $initDTomcatFilePath
chgrp $tomcatSvcGrp $initDTomcatFilePath
chmod g+rwx $initDTomcatFilePath
chown $tomcatSvcUsr $tomcatDirPath
chgrp -R $tomcatSvcGrp $tomcatDirPath
chmod g+rwx $tomcatDirPath
# i have no idea why is it for and why it is not working
#chkconfig --add $tomcatSvcName
#chkconfig --level 234 $tomcatSvcName on
cd $installationPath
chown -R $tomcatSvcUsr *
chgrp -R $tomcatSvcGrp *
chmod g+rwx $tomcatConfPath
cd $tomcatConfPath
chmod g+r *
cd $installationPath
# modify tomcat logging path in conf\logging.properties by adding tomcat folder ${catalina.base}/logs/tomcat
sed -i -e "s~$catalinaLogsSearch~$catalinaLogsReplace~" $loggingPropertiesPath
mkdir $tomcatLogsTomcat
chown -R $tomcatSvcUsr $tomcatLogsTomcat
chgrp -R $tomcatSvcGrp $tomcatLogsTomcat
# modify server.xml set acces log path to logs/access
xmlstarlet ed -L -u /Server/Service/Engine/Host/Valve[#directory]/#directory -v "logs/access" $serverXMLPath
mkdir $tomcatLogsAccess
chown -R $tomcatSvcUsr $tomcatLogsAccess
chgrp -R $tomcatSvcGrp $tomcatLogsAccess
# modify server.xml add maxPostSize tags to http and ajp connectors
xmlstarlet ed -L -a '/Server/Service/Connector[#name="b"]' -t 'elem' -n 'maxPostSize' -v 0 -i '/Server/Service/Connector[not(#name)]' -t 'attr' -n 'maxPostSize' -v "$maxPostSize" $serverXMLPath
#edit tomcat801/bin/catalina.sh
#line 199 change catalina.out file location to
#CATALINA_OUT="$CATALINA_BASE"/logs/tomcat/catalina.out
sed -i -e "s~$catalinaShSearch~$catalinaShReplace~" $catalinaShPath
JAVA_HOME="$jdkDirPath"
export JAVA_HOME
PATH=$JAVA_HOME/bin:$PATH
export PATH
#Add native library for PROD env. to speed up tomcat startup
yum -y install apr-devel openssl-devel
cd $tomcatBinPath
tar -xvzf tomcat-native.tar.gz
cd tomcat-native-1.1.33-src/jni/native
yum -y install gcc
./configure --with-apr=/usr && make && sudo make install
cd /usr/lib
rm -f libtcnative-1.so
ln -s /usr/local/apr/lib/libtcnative-1.so libtcnative-1.so
chown -h $tomcatSvcUsr libtcnative-1.so
chgrp -h $tomcatSvcGrp libtcnative-1.so
cd $tomcatBinPath
rm -rf tomcat-native-1.1.33-src/
#yum -y remove gcc
#yum -y remove apr-devel
#yum -y remove openssl-devel
#yum -y remove epel-release
#yum -y remove xmlstarlet
service $tomcatSvcName start
service $tomcatSvcName status
tomcat801_init.d.txt
#!/bin/bash
#
# tomcat801
#
# chkconfig: - 234 80 20
#
### BEGIN INIT INFO
# Provides: tomcat801
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Default-Start:
# Default-Stop:
# Description: Tomcat 801
# Short-Description: start and stop tomcat
### END INIT INFO
## Source function library.
#. /etc/rc.d/init.d/functions
export JAVA_HOME=/opt/app/java/jdk1.8.0_45
export JAVA_OPTS="-Dfile.encoding=UTF-8"
export PATH=$JAVA_HOME/bin:$PATH
CATALINA_HOME=/opt/app/tomcat801
TOMCAT_USER=tomcatUsr
TOMCAT_SVC=tomcatSvc
SHUTDOWN_WAIT=20
tomcat_pid() {
echo `ps aux | ps -ef | grep $TOMCAT_SVC | grep java | awk ' { print $2 } '`
}
start() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is already running (pid: $pid)"
else
# Start tomcat
echo "Starting tomcat"
ulimit -n 100000
umask 007
/bin/su -p -s /bin/sh $TOMCAT_USER $CATALINA_HOME/bin/startup.sh
fi
return 0
}
stop() {
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Stoping Tomcat"
/bin/su -p -s /bin/sh $TOMCAT_USER $CATALINA_HOME/bin/shutdown.sh
let kwait=$SHUTDOWN_WAIT
count=0;
until [ `ps -p $pid | grep -c $pid` = '0' ] || [ $count -gt $kwait ]
do
echo -n -e "\nwaiting for processes to exit";
sleep 1
let count=$count+1;
echo ""
done
if [ $count -gt $kwait ]; then
echo -n -e "\nkilling processes which didn't stop after $SHUTDOWN_WAIT seconds"
kill -9 $pid
fi
else
echo "Tomcat is not running"
fi
return 0
}
case $1 in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
pid=$(tomcat_pid)
if [ -n "$pid" ]
then
echo "Tomcat is running with pid: $pid"
else
echo "Tomcat is not running"
fi
;;
esac
exit 0
setenv.sh
#! /bin/bash
export CATALINA_OPTS="$CATALINA_OPTS -Xms1024m"
export CATALINA_OPTS="$CATALINA_OPTS -Xmx1024m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:NewSize=512m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxNewSize=512m"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+UseParallelGC"
export CATALINA_OPTS="$CATALINA_OPTS -XX:MaxGCPauseMillis=1500"
export CATALINA_OPTS="$CATALINA_OPTS -XX:GCTimeRatio=9"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+CMSClassUnloadingEnabled"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
export CATALINA_OPTS="$CATALINA_OPTS -server"
export CATALINA_OPTS="$CATALINA_OPTS -XX:+DisableExplicitGC"
if [ -r "$CATALINA_BASE/bin/appenv.sh" ]; then
. "$CATALINA_BASE/bin/appenv.sh"
fi
echo "Using CATALINA_OPTS:"
for arg in $CATALINA_OPTS
do
echo ">> " $arg
done
echo ""
echo "Using JAVA_OPTS:"
for arg in $JAVA_OPTS
do
echo ">> " $arg
done
echo "_______________________________________________"
echo ""
faulty tomcat ps aux result
root 50855 48981 0 07:00 pts/0 00:00:00 grep --color=auto tomcatSvc
working tomcat ps aux result
502 687 1 3 May31 ? 1-17:06:35 /opt/pilot/java/jdk1.8.0_45/bin/java -Djava.util.logging.config.file=/opt/pilot/tomcatSvc/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dfile.encoding=UTF-8 -Xms6000m -Xmx6000m -XX:NewSize=512m -XX:MaxNewSize=512m -XX:+UseParallelGC -XX:MaxGCPauseMillis=1500 -XX:GCTimeRatio=9 -XX:+CMSClassUnloadingEnabled -XX:+HeapDumpOnOutOfMemoryError -server -XX:+DisableExplicitGC -Djava.endorsed.dirs=/opt/pilot/tomcatSvc/endorsed -classpath /opt/pilot/tomcatSvc/bin/bootstrap.jar:/opt/pilot/tomcatSvc/bin/tomcat-juli.jar -Dcatalina.base=/opt/pilot/tomcatSvc-Dcatalina.home=/opt/pilot/tomcatSvc-Djava.io.tmpdir=/opt/pilot/tomcatSvc/temp org.apache.catalina.startup.Bootstrap start
app 23441 23408 0 09:16 pts/0 00:00:00 grep tomcatSvc
The key to understand your code is this command:
tomcat_pid() {
echo `ps aux | ps -ef | grep $TOMCAT_SVC | grep java | awk ' { print $2 } '`
}
It should/could be:
tomcat_pid() {
echo `ps aux | ps -ef | grep $tomcatDirName | grep java | awk ' { print $2 } '`
}
Explanation:
The ps command lists all running processes (including their paths), while grep filter that list based on your "keyword" (in your current code, it's $TOMCAT_SVC/tomcatSvc).
Looking at your "working tomcat ps aux result", I can see that the application is started in folder tomcat802. Furthermore, there is nothing called "tomcatSvc" inside the path:
502 687 1 3 May31 ? 1-17:06:35
/opt/pilot/java/jdk1.8.0_45/bin/java
-Djava.util.logging.config.file=/opt/pilot/tomcat802/conf/logging.properties
-Djava.util.logging.manager=org.apache.juli...
Therefore, if you keep the original command, the system will NOT find the correct PID (simply because there's no literal "tomcatsvc" in your executable path)
If you change to my recommended command, the system will find it.
Warning: this way of finding PID is kind of dangerous, since if you have another running program with path containing "tomcat802", that program could be selected instead. You want to put the absolute path instead of tomcat802; and make sure no one move that folder, or else the code might break.

Jboss 7.1.1 start/stop script

Could someone tell how to start/stop the Jboss-7.1.1 server in MAC using Shell Script.
stop_viewer(){
echo "********* Stopping JBoss Server by killing the process **********";
ps | grep domain.sh | grep -v grep | awk '{print $1}' | xargs kill
ps | grep java | grep -v grep | awk '{print $1}' | xargs kill
ps -ef | grep superuser | grep java | grep -v grep | awk '{print $2}'| xargs kill
echo "********* Stopped JBoss Server by killing the process **********";
}
The above script is working fine in Jboss-7.0.2 to stop the server. But in Jboss-7.1.1, it doesn't stop the server. Please someone help to solve this.
1) First you need to have JBoss downloaded. (I assume you already have valid Java version installed).
2) Once it is downloaded, unzip the folder:
cd /Users/eugene/Downloads
mkdir JBOSS-7
cp /Users/eugene/Downloads/jboss-as-7.1.1.Final.zip /Users/eugene/Downloads/JBOSS-7
cd /Users/eugene/Downloads/JBOSS-7
unzip /Users/eugene/Downloads/jboss-as-7.1.1.Final.zip
3)
cd Users/eugene/Downloads/JBOSS-7/jboss-as-7.1.1.Final/bin
./standalone.sh
If you want to stop it:
ctrl + c
of course your path may be different. If you want to run it in background, then just do:
./standalone.sh &
Stopping it :
ps -ef | grep jboss
You will get an output close to this one:
eugene#eugenes-MacBook-Pro ~/D/J/j/bin> ps -ef | grep jboss
501 1471 1446 0 1:32AM ttys000 0:03.31 /usr/....
And then issue:
kill -9 1471
Finally with JBoss CLI you can execute:
./jboss-cli.sh --connect ":shutdown"
EDIT
The Script seems to do it's job, all you have to do is edit it a bit:
#!/bin/sh
echo "********* Stopping JBoss Server by killing the process **********";
ps -e | grep jboss | grep -v grep | awk '{print $1}' | xargs kill
echo "********* Stopped JBoss Server by killing the process **********";
Notice that I removed a few lines and changed java with jboss
Put this in a file called stopJboss.sh
Then :
sudo chmod +x stopJBoss.sh
Then invoke it when needed:
./stopJBoss.sh
This will work only if you have a single instance of JBoss running, for more you will need a different script.
P.S. I am not a guru in scripting but here is what this line does:
ps -e | grep jboss | grep -v grep | awk '{print $1}' | xargs kill
It is going to look for every process that contains the jboss keyword. But it also going to output the grep command itself, thus you will get an output of two commands, but you need only the first one.
You could run ps -e | grep jboss and see that the output contains two lines and not one.
That is why you invoke grep -v grep - which means : in those two lines found grep for "grep" but invert the result, in this way you omit the second unneeded result.
Then awk '{print $1}' splits the string into tokens and takes the first one, which is the PID that you need and then you pass this PID to the kill command using the xargs command.
To shutdown the server via command line
sh ./bin/jboss-cli.sh --connect command=:shutdown
assuming you are running on localhost and using the default native management port i.e. 9999
if not you need to specify the IP (jboss.bind.address) and the native management port(jboss.management.native.port) configured in standalone.xml
sh ./bin/jboss-cli.sh --connect controller=<IP>:<native-mgmt-port> command=:shutdown
This is how I do it:
ps -ef | grep jboss | grep -v grep | awk '{print $2}' | xargs kill -9
I have this in a bash file that i call killjboss and it works well with me.
After dive on the Google, i managed to put this work:
#!/bin/sh
### BEGIN INIT INFO
# Provides: jboss
# Required-Start: $local_fs $remote_fs $network $syslog
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/Stop JBoss AS v7.1.1
### END INIT INFO
#
#source some script files in order to set and export environmental variables
#as well as add the appropriate executables to $PATH
export JAVA_HOME=/usr/lib/jvm/java-7-oracle
export PATH=$JAVA_HOME/bin:$PATH
export JBOSS_HOME=/home/gaspar/jboss-as-7.1.1.Final
export PATH=$JBOSS_HOME/bin:$PATH
case "$1" in
start)
echo "Starting JBoss AS 7.1.1"
#original:
#sudo -u jboss sh ${JBOSS_HOME}/bin/standalone.sh
#updated:
start-stop-daemon --start --quiet --background --chuid jboss --exec ${JBOSS_HOME}/bin/standalone.sh
;;
stop)
echo "Stopping JBoss AS 7.1.1"
#original:
#sudo -u jboss sh ${JBOSS_HOME}/bin/jboss-admin.sh --connect command=:shutdown
#updated:
sudo -u jboss sh ${JBOSS_HOME}/bin/jboss-cli.sh --connect command=:shutdown
;;
*)
echo "Usage: /etc/init.d/jboss {start|stop}"
exit 1
;;
esac
exit 0
:)

Categories

Resources