LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Bash script - obtain current workdirs of all konsole terminal/sessions (https://www.linuxquestions.org/questions/linux-newbie-8/bash-script-obtain-current-workdirs-of-all-konsole-terminal-sessions-856511/)

Ishrimak 01-15-2011 01:45 PM

Bash script - obtain current workdirs of all konsole terminal/sessions
 
Hello there,

I am trying to write a bash script that would save the current state of my konsole terminals and sessions. I'm using KDE3.X and for some reason the "profile" save does not save the current working directories...

Anyway, I would like to know if there is an elegant way to obtain the current workdir of each terminal and session ?

I've managed to do something with a clever use of DCOP extended functions, but it requires me to start every konsole with the --script option enabled, and I don't want to do that.

Any help would be greatly appreciated !

Cheers

unSpawn 01-16-2011 09:31 AM

A process has a uniqe Process Id or PID ('pgrep konsole' or 'pidof konsole'). The $CWD is the link at /proc/$(pgrep konsole)/cwd. The value you can read like 'readlink -f /proc/$(pgrep konsole)/cwd' but be aware that for multiple PIDs you want to use something like 'pgrep konsole|while read PROC; do readlink -f /proc/$PROC/cwd; done;'.

cin_ 01-16-2011 07:59 PM

throw() hurl()
 
I thought this was a completely reasonable request, and was amazed that my research came up null on a prefab solution.
I wrote some scripts to work this process...

anam()
Code:

# anam -h
usage: anam prints working directory to session log
usage : anam parameters
-n : new : creates new flux session log
-a : append : adds current instance to flux session
-ns [1-9] : new session : creates a new dedicated session
-as [1-9] : append session : appends a dedicated session
-h : helper : opens this help dialogue
add extra parameter : e : to feel Oedipal, and kill your parent process, terminating the terminal, after logging the session instance
#

This script, depending on argument, prints the terminal's working directory to a log file.
The -as and -ns parameters are of particular note. If you have a session you always use, save it to its own dedicated log for continued reuse.

... you can edit the Flux Variables to suit your tastes...
/src
Code:

#!/bin/bash
###FLUX VARIABLES#################
LOG_DIR="/var/log/"            ### 
NM="ptswd"                    ### 
##################################
append ()
{
        if [ $2 ]; then
                FILE="$LOG_DIR$NM.session$2"
        else
                FILE=$LOG_DIR$NM
        fi
if [ -e $FILE ]; then
TTY_MEM=( $( cat $FILE ) )
TTY_MNUM=${#TTY_MEM[@]}
TTY_NM=`tty`
else
        touch $FILE; chmod a+w $FILE;
        TTY_MEM=( $( cat $FILE ) )
        TTY_MNUM=${#TTY_MEM[@]}
        TTY_NM=`tty`
fi

ALT=0
IND=0
while [ $IND -lt $TTY_MNUM ]; do
        if [ "$TTY_NM" == "${TTY_MEM[$IND]}" ]; then
                ALT=17
                TTY_MEM[$IND+1]=$PWD
        fi
let IND=IND+1
done

IND=0
if [ $ALT -eq 17 ]; then
        cat /dev/null > $FILE
while [ $IND -lt $TTY_MNUM ]; do
        echo "${TTY_MEM[$IND]}" "${TTY_MEM[$IND+1]}" >> $FILE
let IND=IND+2
done
else
        echo "$TTY_NM" "$PWD" >> $FILE
fi
}

new () { N_FILE=$LOG_DIR$NM; if [ $2 ]; then N_FILE="$LOG_DIR$NM.session$2"; touch $N_FILE; chmod a+w $N_FILE; cat /dev/null > $N_FILE; else touch $N_FILE; chmod a+x $N_FILE; cat /dev/null > $LOG_DIR$NM; fi; }

helper () { echo -e "usage: `basename $0` prints working directory to session log\nusage : `basename $0` parameters \n-n : new : creates new flux session log\n-a : append : adds current instance to flux session\n-ns [1-9] : new session : creates a new dedicated session\n-as [1-9] : append session : appends a dedicated session\n-h : helper : opens this help dialogue\nadd extra parameter : e : to feel Oedipal, and kill your parent process, terminating the terminal, after logging session"; }

e3x17 () { if [ "$3" == "e" -o "$2" == "e" -o "$1" == "e" ]; then TTY_PID=( $( echo -e `ps h T | cut -c1-6` ) ); TTY_KILL=`ps -p ${TTY_PID[0]} -o ppid=`; kill $TTY_KILL; fi; }

if [ $# -le 3 ]; then
        if [ $3 ]; then
        case "$3" in
                "e");;
                *) helper;;
        esac
        fi
        if [ $2 ]; then
        if [ "$1" == "-as" -o "$1" == "-ns" ]; then       
                case "$2" in
                        [0-9]) ;;
                        *) helper ;;
                esac
        else
                case "$2" in
                "e");;
                *) helper;;
                esac
        fi
        fi
        case "$1" in
                "") append;;
                "e") append; e3x17 $1;;
                "-a") append; e3x17 $2;;
                "-as") append $1 $2; e3x17 $3;;
                "-n") new; append; e3x17 $2;;
                "-ns")new $1 $2; append $1 $2; e3x17 $3;;
                "-h") helper;;
                *) echo "usage: `basename $0` prints working directory to session log. type `basename $0` -h for help"
        esac
else
        helper
fi

noesis()
Code:

# noesis -h
usage : noesis prints working directories to the flux session log of all open pseudo terminal slaves
EXAMPLE : noesis "COMM ARG1 ... ARGn" : if your command has arguments place the entire command in quotes
#

If you have a number of terminals open, and you want to log them all in one go... this is the command to do it.

/src
Code:

#!/bin/bash
###FLUX VARIABLES#################
LOG_DIR="/var/log/"            ###
NM="ptswd"                    ###
##################################
FILE=$LOG_DIR$NM
cat /dev/null > $FILE
IND=1
helper ()
{ echo -e "usage : `basename $0` prints working directories to the flux session log of all open pseudo terminal slaves\nEXAMPLE : `basename $0` \"COMM ARG1 ... ARGn\" : if your command has arguments place the entire command in quotes"; }

gnostic ()
{
echo -e `who | cut -c10-17` > "/tmp/CURR_WHO"
OP_PTS=( $( cat /tmp/CURR_WHO ) )
rm /tmp/CURR_WHO

while [ $IND -lt ${#OP_PTS[@]} ] ; do
        `throw "/dev/""${OP_PTS[$IND]}" "$COMM"`
let IND=IND+1
done
}
if [ $# -gt 0 ]; then
        if [ $# -le 1 ]; then
        case "$1" in
                "-h") helper;;
                *) COMM=$1; gnostic;;
        esac
        fi
else
helper
fi


anamnesis()
Code:

# anamnesis -h
usage : anamnesis recalls a called session from its log file
EXAMPLE : anamnesis LOG_FILENAME : send filename of logged session to recall
DIR : see anam() source for directory and file names
-h : helper : calls this help dialogue
#

This will recall all of the terminals and redirect their working directory to the ones stored in the called log.
For best results run this from the first instance, /dev/pts/0, with no other terminals running. That way the newly opened terminals will be the ones that are redirected as per the log.

...match your directory
...choose your preferred terminal
...fine tune the sleep command for a more seamless transition... My obsessions in mathematics far outweigh my impatience...
/src
Code:

#!/bin/bash
###FLUX VARIABLES#################
LOG_DIR="/var/log/"            ###
PREF_TERM="rxvt"              ###
##################################
helper () { echo -e "usage : `basename $0` recalls a called session from its log file\nEXAMPLE : `basename $0` LOG_FILENAME : send filename of logged session to recall\nDIR : see anam() source for directory and file names\n-h : helper : calls this help dialogue\n"; }

resession () {
IND=1;
HYP_PTS=( $( cat $LOG_DIR$1 ) )
HYP_PTSn=${#HYP_PTS[@]}
let PTS_IND=$(($HYP_PTSn/2))+1
TERMS=$PTS_IND
while [ $IND -le ${#HYP_PTS[@]} ]; do
{
        screen -d -m $PREF_TERM -e bash
let IND=IND+2;
let TERMS=$TERMS+1
}
done

sleep 17;

IND=1
while [ $PTS_IND -lt $TERMS ]; do
{
        throw "/dev/pts/$PTS_IND" "cd ${HYP_PTS[$IND]}"
let IND=$IND+2
let PTS_IND=$PTS_IND+1
}
done
}

if [ $# -eq 1 ]; then
case "$1" in
        "") helper;;
        "-h") helper;;
        *) resession $1;;
esac
else
        helper
fi

You had said Bash, and I tried to get it all done in Bash, but this next part was requiring some severe acrobatics. I turned to C...

throw()
Code:

# throw -h
usage : throw : sends a command to another open psuedo terminal slaves to session log
usage : throw : throw DEVICE_NAME COMMAND
usage : throw : EXAMPLE : throw /dev/pts/1 who
#

This script comes with a partner: hurl(); essentially a quick and easy rewrite of noesis() that allows you to throw() to all open psuedo terminals.

/src
Code:

//main() with args
#include <stdio.h>
//malloc(),realloc()
#include <stdlib.h>
//open(), close()
#include <unistd.h>
//O_RDWR
#include <fcntl.h>
//ioctl(), TIOCSTI
#include <sys/ioctl.h>
//strlen , strcat
#include <string.h>

int main (int argc, char *argv[])
{
    int i,
        fd = 0,
        BASE_ARG = 0,
        DEV_ARG = 1,
        COMM_ARG = 2,
        RET_ARG = 3,       
        MEM_LEN = 0;
    char *COMM,
        *BASE_NM = argv[BASE_ARG],
        *DEV_NM = argv[DEV_ARG],
        *RET = "\n";
  if (argc < 3 || argc > 4)
  {
        printf("usage : %s : sends a command to another open psuedo terminal slaves to session log\n", BASE_NM);
        printf("usage : %s : %s DEVICE_NAME COMMAND \n", BASE_NM, BASE_NM);
        printf("usage : %s : EXAMPLE : %s /dev/pts/17 who\n", BASE_NM, BASE_NM);
  }
  if ( argc > 1 )
  {
        COMM = argv[COMM_ARG];
  } else {
        printf("usage : %s : No command passed\n", BASE_NM);
        exit (0);
  }


  fd = open(argv[DEV_ARG], O_RDWR);
        if (fd == -1)
        {
                printf("usage : %s : device %s not open\n", BASE_NM, DEV_NM);
        }
        for ( i = COMM_ARG; i < argc; i++ )
        {
        MEM_LEN += strlen(argv[i]) + 2;
        if( i > COMM_ARG )
        {
        COMM = (char *)realloc((void *)COMM, MEM_LEN);
        } else
        {       
        COMM = (char *)malloc(MEM_LEN);
        }

        strcat(COMM, argv[i]);
        strcat(COMM, " ");
        }
 
  for (i = 0; COMM[i]; i++) {
        ioctl (fd, TIOCSTI, COMM+i); }
       
  ioctl (fd, TIOCSTI, RET);
  close(fd);
  exit (0);
}

Save this code to FILENAME.c, and then run...
either ...
Code:

make FILENAME_WITHOUT_EXTENSION
or...
Code:

# gcc FILENAME.c -o FILENAME_WITHOUT_EXTENSION
Finally, to be able to use these tools what you can do is place them all in a folder of your choosing, after compiling and chmod a+x'ing, and then add that folder to your PATH...
Code:

# PATH=$PATH:/dir/to/scripts
be good

Ishrimak 01-17-2011 06:18 AM

Thanks a lot for your answers !

@unSpawn: I tried to go your way first, and I have to say I had no idea about the "pgrep" function, which might come handy in many situations. However, all the konsole processes that pgrep gives me have cwd linked to my homedir. More, I cannot find any information on the different sessions that I may have open in each konsole.

@_cin: WOW! You probably spent a lot of time writing these programs/scripts, and I thank you for that. I am going to take some time to fully understand what you wrote, and I'm sure I am going to learn a lot in the process...

unSpawn 01-17-2011 04:05 PM

Quote:

Originally Posted by Ishrimak (Post 4227203)
all the konsole processes that pgrep gives me have cwd linked to my homedir. More, I cannot find any information on the different sessions that I may have open in each konsole.

"Sessions" in this case may be a concept only konsole knows how to deal with internally meaning there is no DE-agnostic way to determine anything.

cin_ 01-17-2011 06:47 PM

Mi Piace
 
My pleasure.
I have more work to do on them yet. I want to be screen() and who() independent, so I will have to study their source for some insight and suggestion into my own desired functionality...

Thank you; it was a great idea.
I learned a lot in making these, and had a lot of fun as well.

I always have more fun on the forums looking for questions than answers.


All times are GMT -5. The time now is 09:38 PM.