Provided by: dish_1.19.1-1_all bug


       dish - tool for parallel sysadmin of multiple hosts


       dish [option]... -e command {-g hosts_file | host_1 host_2 ...}
       dicp {-g hosts_file | -g "user@host_1 ..."} local_file :remote_file
       dicp {-g hosts_file | -g "user@host_1 ..."} :remote_file local_file


       dish - the diligence shell executes commands on several hosts via ssh/rsh/telnet, and also
       makes easy the distribution of files by scp/rcp, a remote password  change,  etc.  It  can
       process hosts in parallel mode.


       -h     Print help message describing shortly all command-line options

       -H, --help
              Comprehensive help including examples

              Print program version and copyright message, then exit

       -V     Display the version number and exit

       -C <dir>
              Configuration  directory  -  $HOME/.dish  is default; In this directory are located
              following configuration files: 'hosts', 'rests', 'pass', and 'options'. When  used,
              this option must be the first argument in the command line string, or be the second
              one if `-D' chosen! Alternatively, one can specify the configuration  directory  by
              defining the environment variable DISH_CONF.

       -CC <dir>
              Same  as  `-C' with fallback to default if local config not found; This means that,
              in case the files 'pass', 'options' or 'rests' are absent in the  given  directory,
              but  such  files  exist  in  $HOME/.dish,  the  latter will be considered. The only
              exception is '$HOME/.dish/hosts' which  will  be  ignored.  Using  this  option  is
              equivalent to changing directory to the opted one and then executing `dish'.

       -c <name>
              Program  (alias  "connector")  and  its  options  used for connecting to the remote
              host(s) - for example `rsh', whereas the spawned process will be "rsh $host <cmd>".
              Your default connector is `ssh'. Furthermore, by using a relevant text-based client
              as connector, one can access various kinds of hosts - switches, databases,  and  so

       -e <cmd>
              Remote command to execute; It can be also set by the environment variable DISH_CMD.

       -E <cmd>
              Execute  command  where  also  the connection part is specified e.g. "-E 'ssh $host
              date'" which is equal to "-e date".  This option  is  incompatible  with  `-c'  and
              `-e'. It can be also set by the environment variable DISH_FUEXE.

       -t     Force  pseudo-tty allocation in ssh; This happens automatically in case of password

       -T <time>
              Timeout for command execution - default 30s (per host)

       -TT <time>
              Total timeout for command execution - default 300s  (all  hosts);  This  option  is
              useful  only  when  hosts  are  processed in sequence and the total processing time
              should not exceed the specified upper bound.

       -x <regex>
              Regular expression for the shell prompt; This value specifies which prompt is to be
              expected  in  the  program's  shell after login into a system by `telnet', `mysql',
              `sqlplus' or other interactive command-line clients (see `-c').  The default  value
              is `(%|\$|#|\>) ?$'.

       -X <regex>
              Regular  expression  for  the  password prompt; It is case-insensitive with default
              value `Password: *$'.

       -AD <regex>
              Regular expression for  the  ssh-prompt  to  add  a  new  host  key  -  `connecting
              (yes/no)?.*' is default

       -AC <str>
              String with the answer to the ssh-prompt to add a new host key - `yes' is default

       -g <file>
              File  with  list  of hosts/ip's/accounts to target; The command will be executed on
              these targets. The default host file is '$HOME/.dish/hosts' - normally per line one
              account  of the form "user@host" (if ssh is your choice for connector). In order to
              join lists use the option  repeatedly.   Alternatively,  the  environment  variable
              DISH_HOSTS could be used to define the target hosts whereas in the specified string
              they have to be separated by blanks. By combining this option with `-r' or `-i' you
              can define various subsets of targeted hosts/accounts.

       -r <file>
              File   with  list  of  resting  hosts/accounts  to  exclude;  The  default  one  is
              '$HOME/.dish/rests'. A "resting host" means one which will  be  excluded  from  the
              targets.  The list of resting hosts or the file name could be specified also by the
              environment variable DISH_RESTS.

       -i <file>
              File with list of hosts/accounts to  overlap  with  targeted  hosts;  There  is  no
              default  file.  Only  overlapping hosts, such included in this list and at the same
              time defined as targets, will be processed.

       -u <name>
              User name - default is your local  user  name;  It  can  be  defined  also  by  the
              environment variable DISH_USER.  Internally the value is accessible by the variable
              $user (see examples). Further, it is irrelevant in case that accounts of  the  form
              "user@host" are processed since they include already the user name.

       -p <passwd>
              Login  password  (-p  ""  =  -pp  =  -a0)  - alias "login authentic" or "a0"; If no
              authentication for login is required (no user- and no password-prompt appear), then
              use  `/dev/null' as password. If the user name is requested, yet the password is an
              empty string, then `/dev/empty' has to be given as  password.  The  value  of  this
              option  could  be  also  a password file (see `-P'). Eventually, one can define the
              password by the environment variable DISH_PASS.

       -a <passwd>
              Additional password for  authentication  (-a  ""  =  -aa  =  -a1)  -  alias  "first
              authentic"  or  "a1"; Inside the spawn process, if a program like `smbmount', `su',
              `ssh', etc. asks for authentication, the a1-password is passed to it. This password
              can be also set by the environment variable DISH_PASS1.

       -A <passwd>
              One more password for authentication (-A "" = -AA = -a2) - alias "second authentic"
              or "a2"; When a spawned process, after one authentication by the a1-password,  asks
              again  for  a  password,  then  a2  is  sent.  This password can be also set by the
              environment variable DISH_PASS2.

       -n <passwd>
              New password in case of password change (-n "" = -nn = -ne)

       -p0    Login without authentication - the same as `-p /dev/null'

       -p1    Set the a1-password to be the same as the login password; This option should not be
              used together with `-p0' and `-a1'.  See example d) bellow.

       -P <file>
              File with password(s); The default password file is '$HOME/.dish/pass'.  It must be
              readable only for the user (file mode 600 or 700), otherwise the program exits with
              error,  but  see also next option. Every line in the file can hold a password entry
              of       the        form:        "password:username:hostname",        alternatively
              "password:::username:::hostname",  or  "password;;;username;;;hostname".   One  can
              specify a list of hosts separated by the `,' or `;' characters. Regular expressions
              for  hostnames  are  also  allowed  (see  the  example  configuration  files in the

       -m     Ignore the access permissions of the password file

       -s [<time>]
              Sequential processing of hosts (default mode); If  a  time  interval  (measured  in
              floating  seconds)  is  specified,  then the program is waiting this amount of time
              before starting to process the next host in the sequence.

       -F     Spawn processes in background -  fork  and  disconnect;  This  way  all  hosts  are
              processed  essentially in parallel!  It's a very powerful option - depending on you
              RAM size and memory utilization, it  shouldn't  be  a  problem  to  process  a  few
              hundreds  of  hosts in parallel. Anyway, be careful - if you have too many hosts on
              the list, your could put your system under load. The  stdout's  of  the  background
              processes  are redirected to '/dev/null', however you can use `-l' or `-L' to write
              the output to files. See also 'bugs and known problems' in the manual page.

       -f     Spawn processes in background without disconnecting from tty; It's the same as `-F'
              whereas  the  stdout's  of the spawned processes are sent to the terminal. Also the
              parent process waits for his children to finish. See also 'bugs and known problems'
              in the manual page.

       -q     Be quiet - skip output from spawn and login; When working with the secure shell, it
              is also convenient to use `ssh' with the `-q' option.

       -Q     Be QUIET - skip any output

       -v     Be verbose (default) - overrides `-q' and `-Q'

       -l <file>
              Log command output to file; The output of the spawned processes is appended to  the

       -L <name>
              Write  a  separate log for every host where <name> denotes the base name of the log
              file. The full name of a log file is defined as "<name>_<user@host>.log".

       -j     Record the invoked command into a journal file with the name '$HOME/.dish/journal';
              It  keeps  the  history  of  the  executed commands and their time of execution. An
              unique identifier is associated with every command.

       -J     Record the invoked command and the  spawned  processes  as  well;  Write  into  the
              journal file the executed command as well as the single processes spawned and their
              time of execution.

       -o <file>
              File  with  command  line  options   passed   to   the   program   -   default   is
              '$HOME/.dish/options';  The options must be written in the file separated - one per
              line. By means of this file, one can modify the standard configuration: set up fork
              mode  to  be  default,  change the default connector, and so forth. When working in
              "copy mode", i.e. by invoking the program as 'dicp', '$HOME/.dish/options.dicp'  is
              considered to be the default options file.

       -d     enable expect's diagnostic output (look at `man expect')

       -D     Debug  mode  (dry-run);  Print  out  environment  variables, config file names, and
              commands to execute, then exit. This option should be used as first in the  command


       You  should  consider that the variables $host and $user are evaluated. Thus $host changes
       dynamically its value to the actual host/account name before a new process is spawned. The
       same is true for $user.

       a) Check the date and uptime on hosts and

              dish -e 'date \; uptime' root@ root@

       b) Distribute '.profile' and '.bashrc' to guest accounts on 'host1' and 'host2'

              dish -E "scp $HOME/.profile $HOME/.bashrc guest@\$host:" host1 host2


              dicp -e "$HOME/.profile $HOME/.bashrc guest@:" host1 host2


              dicp -g "host1 host2" $HOME/.profile $HOME/.bashrc guest@:


              dicp -g "guest@host1 guest@host2" $HOME/.profile $HOME/.bashrc :

       c) Copy remote '.profile' files into the local directory on localhost

              dicp -g "guest@host1 guest@host2 admin@host2" :.profile .profile.\$host

              Here, the name of the target file (local file) will include the remote account name
              in order that the local files have unique names.

       d) Use `ssh' to login on 'host1' and copy from there '.profile' to 'host2'

              Since the list of hosts can not be empty, a dummy host  is  used  to  initiate  the
              process.  The  `-t'  option  is  necessary to force pseudo-tty allocation in `ssh',
              otherwise `ssh' will fail with error on login. A second password  (a1-password)  is
              required for scp-authentication on 'host2':

              dish -a '' -E 'ssh -t user1@host1 scp .profile user2@host2:' dummy_host

              In  case  the  password  of 'user1' and 'user2' is the same, you will be asked only
              once for a login password for user1@host1 if you use `-p1':

              dish -p1 -E 'ssh -t user1@host1 scp .profile user2@host2:' dummy_host

              Or equivalently, and more simple:

              dish -p1 -t -e 'scp .profile user2@host2:' user1@host1

       e) Substitute lines with `START_XNTPD=' by `START_XNTPD="yes"' in /etc/rc.config

              This command is executed as root user on every host listed in 'Hosts.root':

              dish     -u     root      -E      'ssh      $user@$host      "perl      -pi      -e
              \"s/^START_XNTPD=.*\$/START_XNTPD=\\\"yes\\\"/g;\" /etc/rc.config"' -g Hosts.root

       f) Freeze accounts of users on a termination list

              By  using  a  script  called  `',  all  accounts  of  users  found  on
              'Terminate.User.lst' will be frozen today at 24:00 o'clock on both server groups as
              defined in files 'Hosts.1' and 'Hosts.2':

              dish  -E  'ssh  root@$host  "cat Terminate.User.lst | while read UN; do echo \"su -
              admin -c \\\$HOME/bin/ \$UN\" |  at  24:00  ;  done"'  -g  Hosts.1  -g

       g) Print out remote configuration file of an automounter

              Login  as  'admin'  user  on  host, switch to 'root', then cat the file
              '/etc/' and print out the date. The `-a' option causes the program  to  ask
              you for the root-password on remote host:

              dish  -u  admin  -a  ''  -E  'rsh -l $user $host su - root -c \"cat /etc/\;

       h) Install a package on Debian GNU/Linux hosts

              After mounting a fileserver over samba, install from there a debian dish-package on
              all  running servers, yet skip hosts on maintenance.  Three different passwords are
              needed for authentication - one for login, next  for  su-root,  and  the  last  for
              mounting the fileserver:

              dish  -a0  -a1  -a2  -g  Debian.up  -r  Debian.maint  -e  'su - -c \"mount -t smbfs
              //FILESERVER/Packages.Dir /mnt/smb ; dpkg -i /mnt/smb/dish_1.19.1_all.deb\"'

       i) Check for system load >2 using default 'hosts' and 'pass' config files

              dish '(uptime |egrep \" (\[2-9\]|1\[0-9\])\\.\" && hostname) |paste - -'

       j) Query a MySQL database on remote host

              dish -pp -c 'mysql -p -u $user -h' -e 'use mysql; show tables; describe  user;'  -u

       k) Change password concurrently on all hosts/accounts

              We  assume  that  the  list  of  user accounts is contained in file 'Accounts.lst',
              whereas an entry in  the  list  is  of  the  form  "user@hostname".  After  command
              execution,  you will be asked first for the login password (old password), and then
              for the new password which eventually have to retyped correctly:

              dish -p '' -n '' -e passwd -g Accounts.lst

              Or alternatively, processing concurrently and quietly all hosts:

              dish -pp -nn -f -Q -e passwd -g Accounts.lst

              When you want to change password and use `-nn', then the a1-password is  implicitly
              set equal to the login password (a0-password).

       l) Change password from 'root' account (don't use the `-a0' option)

              If you are going to change the root-password on 'remotehost', then try:

              dish -nn -e passwd root@remotehost

              The  same  as  previous, but login as user 'admin' (login password), then switch to
              'root' (a1-password), and finally update the root-password:

              dish -a1 -nn -e 'su -c passwd' admin@remotehost

              Changing the password for  'admin'  on  'localhost',  after  login  as  'root'  via
              `telnet', is done by:

              dish -nn -c telnet -u root -e 'passwd admin' localhost

       Notice  that  for  password  change,  when `-p ""' (or equivalently `-a0' or `-pp') is not
       explicitly used, the assumption is made that `passwd' will not ask for the  old  password,
       as  in case of a password change by 'root'. The same is true also if you can login into an
       account without typing a password, but then `passwd' prompts you to type  the  old  one  -
       this    situation   occurs   when   one   is   using   a   ssh-key   for   login   without
       password-authentication. For such scenario the correct choice of options is `-p0 -aa -nn'.

       In case of properly prepared configuration files in '$HOME/.dish', one can use dish  as  a
       distributed  shell  for  a  virtual  cluster  of  hosts, and run it without specifying any
       program parameters but merely issuing a command, as for instance `dish df -k /'  or  `dicp
       .profile :'.

       As  a  very  last  note,  one  should be aware that in case of authentication by password,
       dish's automated login process is based on the expectation that the login prompt  send  to
       the  terminal  will include the case-insensitive regex-string `Password: *$' (but see also
       `-X'). Otherwise the authentication procedure will fail.


       If Tcl is compiled with thread support, the program hangs when executed in  parallel  mode
       (options  `-f'  or  `-F')  -  it  seems to be a Tcl problem.  Generally, at present Debian
       GNU/Linux (and other debian-based Linux distros as Ubuntu, Knoppix, etc.) pre-package  Tcl
       with multi-thread support enabled.  Therefore, on such systems dish fails to process hosts
       in parallel. In this case you can download the debian source package of  Tcl,  remove  the
       option  "--enable-threads"  in ´debian/rules´, rebuild the package with `dpkg-buildpackage
       -rfakeroot', and eventually install it. It could  be  a  good  idea  to  put  the  freshly
       installed package on hold. Otherwise, you should recompile it on every tcl upgrade.


       Report bugs to <>


       Copyright © 2003-2013 Dimitar Ivanov

       License: GNU GPL version 3 or later <>
       This  is free software: you are free to change and redistribute it.  There is NO WARRANTY,
       to the extent permitted by law.


       expect(1), tcl(3), ssh(1), rsh(1), telnet(1)