You are not logged in.

#2126 2013-06-02 01:45:58

mid-kid
Member
Registered: 2013-05-07
Posts: 177

Re: Post your handy self made command line utilities

karol wrote:

-snip-

Oh, so that's how it works.
Thanks for explaining!


If it ain't broke, you haven't tweaked it enough.

Offline

#2127 2013-06-03 06:00:30

pirateofms
Member
Registered: 2010-05-10
Posts: 19

Re: Post your handy self made command line utilities

This is a small wrapper I put together for pacman to show history.  I'm sure there are other ways to do this, but this is what made sense to me.

# Pacman History commands
function pacman(){
	LOGFILE="/var/log/pacman.log"
	case "$1" in
		-H)	#Show entire history
			cat $LOGFILE
		    ;;
		-Hi) #Show installed history
			cat $LOGFILE | grep 'installed ' | grep -v 'ALPM-SCRIPTLET'
		    ;;
		-Hr) #Show removed packages
			cat $LOGFILE | grep 'removed ' | grep -v 'ALPM-SCRIPTLET'
		    ;;
		-Hu) #Show upgraded packages
			cat $LOGFILE | grep 'upgraded ' | grep -v 'ALPM-SCRIPTLET'
		    ;;
		-Hs) #Search history
			cat $LOGFILE | grep $2
		    ;;
		-Hm) #See install messages, preceded by the package that printed them
			cat $LOGFILE | grep 'ALPM-SCRIPTLET' -B 1
			;;
		*) #Pass everything else to pacman as usual
			/usr/bin/pacman ${1+"$@"}
		esac
}

Offline

#2128 2013-06-03 06:06:17

dodo3773
Member
Registered: 2011-03-17
Posts: 798

Re: Post your handy self made command line utilities

pirateofms wrote:

This is a small wrapper I put together for pacman to show history.  I'm sure there are other ways to do this, but this is what made sense to me.

That's pretty convenient thanks.

Offline

#2129 2013-06-03 06:09:26

dodo3773
Member
Registered: 2011-03-17
Posts: 798

Re: Post your handy self made command line utilities

Found a post somewhere to see aur comments. Edited it a little bit to highlight poster name and delete bottoms lines if less than 5 comments (if there is a better way than what I have below please let me know (I saw a new script someone was writing here but did not want a new package on my system)):

aurcomment () {
lynx -dump https://aur.archlinux.org/packages/$1/?comments=all | grep --max-count=5 --after-context=99 --color=never "Comment by" | sed -n '/AUR v2.2.0/q;p' | grep --color=always -E '^|Comment by .*|'
}

Offline

#2130 2013-06-04 13:16:10

skanky
Member
From: WAIS
Registered: 2009-10-23
Posts: 1,838

Re: Post your handy self made command line utilities

pirateofms wrote:

This is a small wrapper I put together for pacman to show history.  I'm sure there are other ways to do this, but this is what made sense to me.

Just one point, you don't need to use cat as you can specify the filename to the first grep.

Hope you don't mind, but here's a version of that useful script (thanks) that uses awk. I wrote it as an exercise as I've not done much awk scripting for a while and I'm getting rusty.
There are probably ways to improve it (the ALPM-SCRIPTLET bit, for a start), but time is also an factor, at the moment. It's a bit longer than yours but has a little more functionality.

I've only tested it a bit, and the pacman pass-though is a bit brittle (I probably wouldn't use that much).

#!/usr/bin/bash

PACLOGFILE="/var/log/pacman.log"
NREC=0
HISTPAGER=
CMD=cat

searchhist () {
awk 'BEGIN { ix = 0 }

    /ALPM-SCRIPTLET/ { next }
    /'$SEARCH'/ { found[++ix] = $0 }

    END {   if ( nrec == 0 ) nrec = ix;
            startpoint = (ix - nrec) + 1
            for ( i = startpoint; i <= ix; i++) 
                    print found[i];
    } '  nrec=$NREC $PACLOGFILE 
}

while getopts ":n:l:p" opt; do
        case $opt in
                n ) NREC=$OPTARG
                ;;
                l ) PACLOGFILE="$OPTARG"
                ;;
                p ) HISTPAGER="| $PAGER"
                ;;
                ? ) /usr/bin/pacman "$@" 
                    exit
        esac
done

shift $((OPTIND - 1))

case "$1" in
        H ) #Show entire history
            if [[ $NREC -gt 0 ]]; then
                CMD="tail -n $NREC"
            fi
            eval $CMD $PACLOGFILE $HISTPAGER
            exit
            ;;

        I ) #Show installed history
            SEARCH=installed
            ;;

        R ) #Show removed packages
            SEARCH=removed
            ;;

        U ) #Show upgraded packages
            SEARCH=upgraded
            ;;

        S ) #Search history
            SEARCH="$2"
            ;;

        P ) #See install messages, preceded by the package that printed them
                eval grep 'ALPM-SCRIPTLET' -B 1 $PACLOGFILE $HISTPAGER
            ;;

        * )     echo "Invalid command: " $1
                exit -1
esac

eval searchhist $HISTPAGER

"...one cannot be angry when one looks at a penguin."  - John Ruskin
"Life in general is a bit shit, and so too is the internet. And that's all there is." - scepticisle

Offline

#2131 2013-06-04 13:37:44

Trilby
Forum Moderator
From: Massachusetts, USA
Registered: 2011-11-29
Posts: 13,699
Website

Re: Post your handy self made command line utilities

I'm not sure I see the need for the awk array.  Wouldn't this do the same thing?

awk '
    /ALPM-SCRIPTLET/ { next }
    /'$SEARCH'/ { print $0 }
'  $PACLOGFILE  | tail -$NREC

InterrobangSlider
• How's my coding? See this page.
• How's my moderating? Feel free to email any concerns, complaints, or objections.

Offline

#2132 2013-06-04 13:58:08

skanky
Member
From: WAIS
Registered: 2009-10-23
Posts: 1,838

Re: Post your handy self made command line utilities

Trilby wrote:

I'm not sure I see the need for the awk array.  Wouldn't this do the same thing?

awk '
    /ALPM-SCRIPTLET/ { next }
    /'$SEARCH'/ { print $0 }
'  $PACLOGFILE  | tail -$NREC

Yeah, but I just wanted to do the tail in awk. There's probaby no good reason to do so, and I should have mentioned that in my post (EDIT: I had intended for it all to be in just awk, but scaled that back part way through).

Last edited by skanky (2013-06-04 16:41:34)


"...one cannot be angry when one looks at a penguin."  - John Ruskin
"Life in general is a bit shit, and so too is the internet. And that's all there is." - scepticisle

Offline

#2133 2013-06-04 16:19:37

pirateofms
Member
Registered: 2010-05-10
Posts: 19

Re: Post your handy self made command line utilities

Just one point, you don't need to use cat as you can specify the filename to the first grep.

I always forget about that. 

I'm honestly not much of a scripter, more of just a tinkerer, so I usually end up making things overly simple or overly complicated.  Heh.

Offline

#2134 2013-06-04 16:40:40

skanky
Member
From: WAIS
Registered: 2009-10-23
Posts: 1,838

Re: Post your handy self made command line utilities

pirateofms wrote:

Just one point, you don't need to use cat as you can specify the filename to the first grep.

I always forget about that. 

I'm honestly not much of a scripter, more of just a tinkerer, so I usually end up making things overly simple or overly complicated.  Heh.

I know the feeling.


"...one cannot be angry when one looks at a penguin."  - John Ruskin
"Life in general is a bit shit, and so too is the internet. And that's all there is." - scepticisle

Offline

#2135 2013-06-06 12:50:21

kokoko3k
Member
Registered: 2008-11-14
Posts: 1,471

Re: Post your handy self made command line utilities

This in my ~.bashrc:

benice="renice -n 19 -p $$ && ionice -c3 -p $$ && ionice -p $$"
berude="sudo renice -n -19 -p $$ && sudo ionice -c1 -p $$ && ionice -p $$"

At prompt, benice/berude will change the priority of the current shell.

Last edited by kokoko3k (2013-06-06 12:52:52)

Offline

#2136 2013-06-06 13:00:01

drcouzelis
Member
From: Connecticut, USA
Registered: 2009-11-09
Posts: 3,441
Website

Re: Post your handy self made command line utilities

kokoko3k wrote:

This in my ~.bashrc:

benice="renice -n 19 -p $$ && ionice -c3 -p $$ && ionice -p $$"
berude="sudo renice -n -19 -p $$ && sudo ionice -c1 -p $$ && ionice -p $$"

At prompt, benice/berude will change the priority of the current shell.

So, if I understand you correctly, you open a new terminal window, type "benice", then use that same terminal window to compile the Linux kernel, your computer is still usable?

That is nice! Good idea. I will try using it too. smile

Offline

#2137 2013-06-06 15:18:34

kokoko3k
Member
Registered: 2008-11-14
Posts: 1,471

Re: Post your handy self made command line utilities

yep smile

Offline

#2138 2013-06-08 15:59:22

ajbibb
Member
Registered: 2012-02-12
Posts: 118

Re: Post your handy self made command line utilities

I wanted to have my i3bar to be able to display weather alerts.  There are a couple of good CLI weather programs in the AUR, and also some weather scripts up thread, but nothing quite what I wanted though.  This script will download any active alerts, and the current weather conditions.  Output is three files.  One contains the number of active alerts which I use for color coding the text entry in my i3bar, one file contains the text to display in the bar (either an alert notification or current temperature and pressure) , the last file contains a detailed description of the weather alert I can bind to an obscure key combination in i3.  The script can be called by the program that controls i3status, or as a cron job.

The weather locations are hard coded in the script.  Just change to the location you are interested in.  Since it uses the National Weather Service alert system I'm afraid this is useful only in the US and territories.



#!/bin/bash
#
# Script to obtain National Weather service alert and current observation data.  Used
# to provide text input to a status bar.  Specifically we append to i3status for display
# in the i3bar.
#
# This script will produce 3 files that can be used by other programs.
# short summary - text which can be displayed in the bar, try to limit the number of characters.
#                 Right now it will display "NWS Alert" if there is a current weather alert,
#                 if there is no alert the temperature and pressure are displayed
# long summary -  will display the full text of any active weather alert.
# alert level  -  contains a single line with a single number of zero or greater.  The number
#                 is the number of current alerts, with zero meaning no alerts.  May be used
#                 to provide data to color code the status bar text
#
# This program may be called either as a cron job, or by the program that creates the
# status bar.  There are two timers internal to the program, one for ATOM/XML alerts, the other
# for METAR (current conditions).  This program can be called as often as you like, but new
# data will only be downloaded based on the setting in these timers which will check
# the age of the previous download.
#
# Notes on parsing XML in BASH.  From what I can find on the internet parsing an XML
# file in BASH is supposed to be next to impossible.  In this script we are not really
# parsing the XML, what we are doing is more like sifting through the debris of a
# crash site looking for something that may be useful.  This is only possible because we
# know something about the contents of the file before we start.
#
#
##################################### Functions ###############################################
#
# function to sift through a metar/txt file.  Grab whatever data you to want to show in the
# status bar
#
siftMETAR()
{
  # local variables
  local s=
  local temp=
  local bar=
  local trend=
  local readonly p_rising=▲
  local readonly p_falling=▼
  local readonly p_steady=─

  #echo -e  "\nProcessing: ${temppath}/${metarcode}.xml"

  # if the metarfile exists get temperature, pressure and pressure trends
  if [[ -e ${temppath}/${metarfile} ]]; then

    # extract the temperature/dewpoint entry, isolate temperature, convert minus temperature to numeric value
    temp=$(awk -v RS="[ \t\n]+" '/^M?[[:digit:]]{2}\/M?[[:digit:]]{2}$/ {print $0}' "${temppath}/${metarfile}")
    temp=$(echo ${temp} | cut -d '/' -f 1)
    temp=$(echo ${temp} | sed 's|M|-|' )

    # now convert celsius temperature to fahrenheit using the magic of awk floating point math
    temp=$(awk -v t=${temp} 'BEGIN {printf "%.1f\n", t*9/5+32}')

    # extract the pressure data (field format Annnn), strip leading A, format properly
    bar=$(awk -v RS="[ \t\n]+" '/^A[[:digit:]]{4}$/ {print $0}' "${temppath}/${metarfile}")
    bar=$(echo ${bar#A})
    bar=$(awk -v b=${bar} 'BEGIN {printf "%.2f\n", b/100.0}')

    # look for pressure trends (field format 5nnnn), it is an optional data field so may not exist
    trend=$(awk -v RS="[ \t\n]+" '/^5[[:digit:]]{4}$/ {print $0}' "${temppath}/${metarfile}")
    if [[ -n ${trend} ]]; then
      case "${trend}" in
      50??? ) trend=${p_falling}  ;;
      51??? ) trend=${p_rising}   ;;
      52??? ) trend=${p_rising}   ;;
      53??? ) trend=${p_rising}   ;;
      54??? ) trend=${p_steady}   ;;
      55??? ) trend=${p_rising}   ;;
      56??? ) trend=${p_falling}  ;;
      57??? ) trend=${p_falling}  ;;
      58??? ) trend=${p_falling}  ;;
      esac
    fi

  fi

  # format the string to display
  [[ -n ${temp} ]] && s="T:${temp}°F" || s="T: --"
  [[ -n ${bar} ]] && s="${s} B:${bar}${trend}" || s="${s} B: --"

  # write the string to s_sum
  echo ${s} > "${temppath}/${s_sum}"

  return 0
}

#
# function to sift through the atom/xml file.  The NWS uses the atom/xml feed to alert you
# that there are alerts (hey - it is the goverment).  Split the atom file at each <entry> tag.
# Inside each new entry file look for the <url> field and then download and process the file
# pointed to by the url.  This file contains detailed information about the specific alert.
#
siftATOM()
{
  # local variables
  local cntr=
  local url=

  #echo -e  "\nProcessing: ${temppath}/${atomfile}"

  # split the atom file into individual files at each <entry> tag.  Only works if there are
  # no nested <entry> tags.  The resulting files are no longer valid XML, but we don't really
  # care.  We are sifting not parsing.
  awk -v n=0 -v p="${temppath}" '/<entry>/{close("entry"n);n++;next} {print > p"/entry"n}' "${temppath}/${atomfile}"

  # search the split files for titles and url's
  cntr=1  # only the files for entry1 and above contain anything we want
  while [[ -e "${temppath}/entry${cntr}" ]]; do
    url=$(awk 'BEGIN {RS="./>"; FS="<link href=.";} { print $2 }'  "${temppath}/entry${cntr}")

    # download the cap file determined by the url in each entry file, if there is a description tag
    # it should describe the alert, if no description tag get the title field which should then say
    # there are no alerts. Use this data to fillout the l_sum file.
    curl ${url} > "${temppath}/cap${cntr}"
    if [[ -n $(grep "description"  "${temppath}/cap${cntr}") ]]; then
      echo "====================================================================" >> "${temppath}/${l_sum}"
      awk 'BEGIN {RS="</event>"; FS="<event>";} { print $2 }'  "${temppath}/cap${cntr}" >> "${temppath}/${l_sum}"
      awk 'BEGIN {RS="</description>"; FS="<description>";} { print $2 }'  "${temppath}/cap${cntr}" >> "${temppath}/${l_sum}"
      ((alert_level+=1))
    else
      awk 'BEGIN {RS="</title>"; FS="<title>";} { print $2 }'  "${temppath}/entry${cntr}">> "${temppath}/${l_sum}"
    fi

    ((cntr+=1))
  done

  return 0
}

#
##################################### Main Script #############################################
#
# program constants
readonly temppath="/tmp/myles_weather"  # keep weather data in a temp file system
readonly deplist="curl awk sed"         # packages this script needs
readonly s_sum="short_sum.txt"          # a text file containing the data we wish to display in statusbar
readonly l_sum="long_sum.txt"           # a text file containg more detailed information
readonly a_lev="alert_level.txt"        # a text file containing the number of current alerts there are
readonly alert_txt="NWS Alert"          # text you want to show when there is an active alert
readonly a_interval=(5*60)              # number of seconds between requests for new ATOM/XML (alert) files
readonly m_interval=(60*60)             # number of seconds between requests for new METAR (current conditions) files
readonly now=$(date +%s)                # the current date, time, etc

#
# temporary constants - move these to a conf file eventually
# find your county code here: http://alerts.weather.gov/
# find your metar code here: http://w1.weather.gov/xml/current_obs/ (pick select a state)
# change values below for your location.

# Chittenden County, VT
readonly countycode="VTC007"
readonly metarcode="KBTV"

# Leavenworth, KS
#readonly countycode="KSZ103"
#readonly metarcode="KMCI"

#
# program variables
deps=
atomfile=
alert_level=0   # the number of alerts in effect, zero = no active alerts
lastmod=
metarfile=

#
# make sure dependencies are met
for d in ${deplist}; do
  [[ -z $(which ${d} 2>/dev/null) ]] && deps="${d} ${deps}"
done

if [[ -n ${deps} ]]; then
  echo -e "\nDependencies not fulfilled, missing the following package(s): ${deps}\nObtain them by running this command as root:"
  echo "  pacman -Sy ${deps}"
  echo "exiting"
  exit 1
fi

#
# make sure the directories we need exist
[[ ! -e ${temppath} ]] && mkdir -p "${temppath}"

#
# download the NWS alert file (atom/xml) if the old one has expired. erase
# old files first.  If download was successful process the file using siftAtom
atomfile="wwaatmget.php?x=${countycode}&y=1"
[[ -e "${temppath}/${atomfile}" ]] && lastmod=$(stat -c%Z "${temppath}/${atomfile}") || lastmod=0
if [[ $((${now}-${lastmod})) -gt ${a_interval} ]]; then
  rm -f "${temppath}/cap*" 2> /dev/null
  rm -f "${temppath}/entry*" 2> /dev/null
  rm -f "${temppath}/${atomfile}" 2> /dev/null
  rm -f "${temppath}/${s_sum}" 2> /dev/null
  rm -f "${temppath}/${l_sum}" 2> /dev/null
  rm -f "${temppath}/${a_lev}" 2> /dev/null

  curl "http://alerts.weather.gov/cap/${atomfile}" > "${temppath}/${atomfile}"

  # if we got the file sift through it looking for alert data. The function will also
  # fill in the l_sum text file
  if [[ ${?} -eq 0 ]]; then
    [[ ${?} == 0 ]] && siftATOM

    # provide the alert level to the alert level text file
    [[ ${?} == 0 ]] && echo "${alert_level}" > "${temppath}/${a_lev}"

   else
    rm -f "${temppath}/${atomfile}"
  fi
fi

# download a new METAR file if the old one has expired
metarfile="${metarcode}.1.txt"
[[ -e "${temppath}/${metarfile}" ]] && lastmod=$(stat -c%Z "${temppath}/${metarfile}") || lastmod=0
if [[ $((${now}-${lastmod})) -gt ${m_interval} ]]; then
  rm -f "${temppath}/${metarfile}" 2> /dev/null
  rm -f "${temppath}/${s_sum}" 2> /dev/null
  curl "http://w1.weather.gov/data/METAR/${metarfile}" > "${temppath}/${metarfile}"
  [[ ${?} -gt 0 ]] && rm -f "${temppath}/${metarfile}"
fi

# create a new s_sum file if none exists
if [[ ! -e ${temppath}/${s_sum} ]]; then
  if [[ $(cat ${temppath}/${a_lev}) -eq 0 ]]; then
   siftMETAR
  else
    echo ${alert_txt} > "${temppath}/${s_sum}"
  fi
fi

exit "${?}"

Last edited by ajbibb (2013-07-19 13:47:35)

Offline

#2139 2013-06-12 18:50:30

Thaodan
Member
From: Dortmund, Nordrein-Westfalen
Registered: 2012-04-28
Posts: 434

Re: Post your handy self made command line utilities

My script to convert all FLAC files in a dir to ogg files in target dir:

#!/bin/sh
# Recursively find FLAC files starting in current directory 
# and convert them to ogg vorbis files
appname=${0##*/}
MAX_ARGS=2
# remove umlauts for FAT file systems
umlaut_cleaner() {
    echo "$1" | sed -e 's|ö|o|g' -e 's|ü|u|g' -e 's|ä|a|g'
}

fatfix() {
    umlaut_cleaner "$1" | sed -e 's|:||g' 
}
main() {
  find "$TARGET_DIR" -name *.flac  | while read FLACFILE
    do
      # Grab the id3 tags from the FLAC file
      ARTIST=$(metaflac "$FLACFILE" --show-tag=ARTIST | sed s/.*=//g)
      TITLE=$(metaflac "$FLACFILE" --show-tag=TITLE | sed s/.*=//g)
      ALBUM=$(metaflac "$FLACFILE" --show-tag=ALBUM | sed s/.*=//g)
      GENRE=$(metaflac "$FLACFILE" --show-tag=GENRE | sed s/.*=//g)
      TRACKNUMBER=$(metaflac "$FLACFILE" --show-tag=TRACKNUMBER | sed s/.*=//g)
      DATE=$(metaflac "$FLACFILE" --show-tag=DATE | sed s/.*=//g)
      COVERART=$(metaflac --export-picture-to=- "$FLACFILE" | base64 --wrap=0 -)
      # A little shell globbing to get the filename
      # (everything after the rightmost "/")
      FILENAME=${FLACFILE##*/}
      # Build the output path and rename the file
      OGGFILE=$(echo "$DESTINATION_DIR/$ARTIST/$ALBUM/$FILENAME" | sed s/\.flac$/.ogg/g)
      if [ $fatsave ] ; then
	 OGGFILE=$(fatfix "$OGGFILE")
      fi
      # Convert to OGG at 320kbps (use -q6 for 192kbps)
      oggenc -q9 --discard-comments -a "$ARTIST" -t "$TITLE" -l "$ALBUM" -G "$GENRE" -N "$TRACKNUMBER" -d "$DATE" -o "$OGGFILE" "$FLACFILE"
      if [ $deprecovertag ] ; then
	  vorbiscomment -a -c "COVERTAG=$COVERTAG" "$OGGFILE"
      else
	  vorbiscomment -a  -t "METADATA_BLOCK_PICTURE=$COVERART" "$OGGFILE"
      fi
  done 
  
  if [ $coverd ] ; then
      printf "$COVERART" > "${OGGFILE##*/}"/cover.jpg
  fi
}

print_help() {
cat <<_HELP_MSG
  $appname - usage:
      $appname [options] <target_dir> <destination_dir>
options
  --fatfix           use fat save filenames
  --coverd           save cover.jpg file in album dir
  --depre-covertag   use depreacted COVERTAG comment in ogg file
_HELP_MSG
}

case $1 in 
  -h|--help) print_help;;
  *)
  if [ $# -ge $MAX_ARGS ] ; then
    while [ ! $# = $MAX_ARGS ] ; do
      case "$1" in
	  --stub) echo stub ; shift ;;
	  --fat-save) fatsave=True; shift ;;
	  --coverd) coverd=True ; shift ;;
	  --depre-covertag) deprecovertag=True; shift ;;
	  --) shift $(( $# - $MAX_ARGS )); break ;;	
	  --*|-*) 
	      echo "unkown option"
	      exit 1
	      ;;
  
      esac
    done
      
    TARGET_DIR=$1
    DESTINATION_DIR=$2
    shift 2
    main
  else
    echo "no or to less arguments given"
  fi
esac

With some options to care for fat drives and older audio players.

Last edited by Thaodan (2013-06-12 21:37:26)


Linux odin 3.13.1-pf #1 SMP PREEMPT Wed Mar 5 21:47:28 CET 2014 x86_64 GNU/Linux

Offline

#2140 2013-06-24 22:16:32

Thaodan
Member
From: Dortmund, Nordrein-Westfalen
Registered: 2012-04-28
Posts: 434

Re: Post your handy self made command line utilities

My wine cli prefix programm starter, I know its fat.
Syntax: usenew [ARGS] <prefix or -p> <program>
If -g is given all output and input is capured using kdialog, zenity or even xdialog (most stuff don't works with xdialog).
It supports using different wine version via -b or WINE_PATH enviroment var.
It support using explorer to create a virtual desktop if -d is given.
If -p is given it asks for prefix (combined with -g its a god way to start a program out of a file manager like dolphin).

#!/bin/sh

# wine prefix chooser and manager
#
# Copyright (C) 2012  Björn Bidar
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# variables
#  version vars:
############################################
USE_VER=3.2
USE_REV=a57afb2812

appname=$(basename $0)
detectDE() 
# detect which DE is running
# taken from xdg-email script 
{
    if [ x"$KDE_FULL_SESSION" = x"true" ]; then 
	DE=kde;
    elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then 
	DE=gnome;
    elif `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1` ; then 
	DE=gnome;
    elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then 
	DE=xfce;
    else 
	DE=generic 
    fi
}


d_msg() # display msgs and get input 
#########################################################################################################################
# NOTE: needs kdialog ( or zenity ) to display graphical messages and get input in gui					#
#########################################################################################################################
# usage:														#
#  d_msg [modifer] topic msg												#
#  modifers:														#
#  ! msg is an error/faile message											#
#  i msg is an msg/input ( work's not properly in cgi and with xmessage : terminal)					#
#  f msg is an yes/no msg/test												#
#  l msg is an list of items ( nyi in cgi: terminal)									#
#    no modifer msg is an normal msg											#
#########################################################################################################################
#															#
# vars:															#
# DMSG_GUI_APP=`detectDE` (default)  	# d_msg detects wich DE is installed and uses the equal dialog for displaing	#
# DMSG_GUI_APP=generic 			# only set if dialog for DE not found						#
# DMSG_GUI_APP=gnome|xfce 		# with this you can force d_msg to use zenity					#
# DMSG_GUI_APP=kde 			# with this you can force d_msg to use kdialog					#
#															#
# DMSG_GUI                      	# if not zero use graphical dialog, else cfg gui				#
# DMSG_ICON				# icon that d_msg uses when is runned in gui mode if not set icon xorg is used 	#
#															#
#															#
# DMSG_APP 				# say DMSG to use $DMSG_APP in cli possible vara are dialog and cgi_dialog	#  
#															#
#															#   
#															#
#															#
#########################################################################################################################
{
    if [ ! $# -lt 2 ] ; then
	unset dmsg_return_status
	if [  "${DMSG_GUI}" = true ] || [ ! $DMSG_GUI = 0 ] ; then
	    if [  -z "$DMSG_GUI_APP" ] ; then
		detectDE
		DMSG_GUI_APP=$DE
	    case "$DMSG_GUI_APP" in 
		kde)  
		    which  kdialog  > /dev/null  || \
			{ which > /dev/null  zenity  && DMSG_GUI_APP=gnome  || DMSG_GUI_APP=generic; }
		    ;;
		gnome|xfce) which zenity   > /dev/null   || \
		   (  which  kdialog  > /dev/null  && DMSG_GUI_APP=kde || \
		    DMSG_GUI_APP=generic );;
		*)  which kdialog > /dev/null  && DMSG_GUI_APP=kde || { which zenity > /dev/null && DMSG_GUI_APP=zenity \
		    || DMSG_GUI_APP=generic; }
		    ;; 
	    esac 
	fi
	    
	    case $DMSG_GUI_APP in 
		kde)
		    case $1 in 
		    !)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}" --title "$2" --error "$3" 
			dmsg_return_status=${DMSG_ERR_STAUS:=1}  
			;;
		    i) kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}" --title "$2" --inputbox "$3" 
			dmsg_return_status=$?
			;;
		    l)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}" --title "$2" --menu \
			"$3" "$4" "$5" "$6" "$7" "$8" "$9" 
			shift ; dmsg_return_status=$? ;;
		    f)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}"  --title "$2" --yesno "$3" 
			dmsg_return_status=$? ;;
		    *)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}"  --title "$1" --msgbox "$2" 
			dmsg_return_status=$? ;;
		    esac
		    ;;
	    xfce|gnome) #nyi impleted
		    case $1 in 
		    !) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2 - ${DMSG_APPNAME:=$appname}" --error --text="$3"
			dmsg_return_status=${DMSG_ERR_STAUS:=1}   
			;;
		    i) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2 - ${DMSG_APPNAME:=$appname}" --entry --text="$3"
			dmsg_return_status=$? 
			;;
		    l) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2  -${APPNAME:=$appname}" --column='' --text="$3"\
                        --list 
		       dmsg_return_status=$? 
		       ;;
		    f) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2  -${APPNAME:=$appname}" --question --text="$3" 
			dmsg_return_status=$? 
			;;
		    *) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$1  -${APPNAME:=$appname}" --info --text="$2" 
			dmsg_return_status=$? ;;
		esac
		;;
	 *)
		    case $1 in
		    !) xmessage -center -title "$2 - ${APPNAME:=$appname}" "err: "$3"" ;
			dmsg_return_status=${DMSG_ERR_STAUS:=1} 
			;;
		    f) xmessage -center -title "$2  -${APPNAME:=$appname}" -buttons no:1,yes:0 "$3" 
			dmsg_return_status=$? 
			;;	
		    i) 
			if [ -z $buttons ] ; then
			    DMSG_XBUTTONS='not:1,set:2'
			fi
			xmessage -center -title "$appname - "$2"" -print -buttons $buttons "$3"
			dmsg_return_status=$?
			;;
		    l) xmessage -center -title "$2 - ${APPNAME:=$appname}" -print -buttons "$3","$4","$5","$6","$7","$8","$9" ; dmsg_return_status=$? ;;
		    *) xmessage -center -title "$1 - ${APPNAME:=$appname}" "$2" ; dmsg_return_status=$? ;;
		    esac
		    ;;
	    esac
	else
	      case ${DMSG_APP:-native} in
	      dialog)
		  case "$1" in 
	              !) dialog --title "$2 -${APPNAME:=$appname}" --infobox "error:$3" 0 0 ; dmsg_return_status=${DMSG_ERR_STAUS:=1};;
		      #!) cgi_dialog ! "$3" ; dmsg_return_status=${DMG_ERR_STAUS:=1}  ;;
		      f) dialog --title "$2 - ${APPNAME:=$appname}" --yesno "$3"   0 0 
			  dmsg_return_status=$?
			  ;;
		      i) dialog --title "$2 - ${APPNAME:=$appname}" --inputbox "$3" 0 0
			  dmsg_return_status=$?		 
			  ;;
		      *) dialog --title "$1 -${APPNAME:=$appname}" --infobox "$2" 0 0  ;;
		      #*) cgi_dialog "$2" ; dmsg_return_status=$? ;;
		  esac
		  ;;
	      native)
		  case "$1" in
		      !) echo  "$3" ; dmsg_return_status=${DMSG_ERR_STAUS:=1} ;;
		      f)  echo ""$3" y|n"
			  read a 
			  if [ ! $a = y ] ; then
			      dmsg_return_status=1;
			  fi
			  ;;
		      i) 
			  echo "$3"
			  read  a 
			  if [ -z "$a" ] ; then
			      dmsg_return_status=1;
			  fi
			  ;;
		      *)  echo "$2"   ; dsmg_return_status=$? ;;
		  esac
		  ;;
	      esac
	      
	fi
    fi
    return $dmsg_return_status
}

## functions for fake_arrays ########################################################################
# fake arrays are array emulated by using : as $IFS
#
#
#####################################################################################################
# NOTE:
# unlike arrays normal arrays the index of arrays starts with 1 instead of 0
# if a fake_array function gets a 0 as index parameter all entrys in the array where selected 
#
# 	for example:
#
#		var=`read_farray fu:bar 0`
#	       +var='fu bar'
#####################################################################################################	

get_farray_lenght() { # get lenght of fake array
    if [ $# -ge 1 ] ; then 
	old_ifs=$IFS
	IFS=:
	for var in $1 ; do
	    get_farry_lenght_count=$(( $get_farry_lenght_count + 1 ))
	done
	IFS=$old_ifs
	echo  ${get_farry_lenght_count:-0}
	unset get_farry_lenght_count var
    else
	echo 0
    fi
}

read_farray() { # read fake array
    if [ $# = 2 ] ; then
	old_ifs=$IFS
	IFS=:
	for var in  $1 ; do
	    _read_farry_count=$(( $_read_farry_count + 1 ))
	    if [ $2 -eq  $_read_farry_count ] || [ $2 -eq 0 ] ; then
		if [ ! -z $var ] ; then
		    echo $var
		fi
	    fi
	done
	IFS=$old_ifs
    fi
    unset _read_farry_count  var
}

write_farray() {  # write fake array   
    if [ $# -eq 3 ] ; then
	farry_content=$( eval echo \$$1)
	if [ ! -z "$farry_content" ] ; then 
		    if [ $( get_farray_lenght "$farry_content") = $(( $2 - 1 )) ] ; then
			eval $1=$farry_content:$3
		    else
			eval $( echo $1)=$( echo $farry_content | sed "s/$(read_farray $farry_content $2 )/$3/")
		    fi
	elif [ $2 = 1 ] ; then
	    eval $1=$3
	else
	    return 1
	fi
    fi
}


# settings
############################################ 
test_input () { 
  DMSG_test_input_N=$(( $# + 1 ))
  DMSG_test_input_errmsg="$( read_farray "$err_input_messages" $DMSG_test_input_N)"
  if [ -n "$DMSG_test_input_errmsg" ] ; then
      d_msg ! 'wrong input' "$DMSG_test_input_errmsg"
      if [   $# = 0   ]; then
	return 1
      else
	  return 
      fi
  fi
}
DMSG_ICON=wine  # icon for gui d_msg output
DMSG_DIALOG_DISABLED=true # we dont need dialog for cli so disable it

#!/bin/sh 
USE_REV=a57afb2812
 
prepare() { # init vars that will exported from wine to the shell
  userprofile=`${WINE:=wine} cmd.exe /c echo %userprofile%`
  appdata=` ${WINE:=wine} cmd.exe /c echo %APPDATA%`
  system_drive=` ${WINE:=wine} cmd.exe /c echo %systemdrive%`
  program_files=` ${WINE:=wine}  cmd.exe /c echo %programfiles%`
  winsysdir=` ${WINE:=wine} cmd.exe /c echo %winsysdir%`
  windir=` ${WINE:=wine} cmd.exe /c echo %windir%`
  windir=`winepath  -u $windir`
  winsysdir=`winepath -u $winsysdir`
  userprofile=`winepath -u $userprofile`
  appdata=`winepath -u $appdata`
  system_drive=`winepath -u  $system_drive`
  program_files=`winepath $program_files`
}

check_wineserver() {
   if ps ax | grep wineserver | grep -vq grep ; then
    if d_msg f 'other wineserver' "An other wineserver is running, kill him (any other procces that run on wineserver will killed too)?" ; then
	  pkill wineserver  #--uid $(id -ru)  
	  return 0
    else
      return $?
    fi
  fi
}
set_wine_ver () { # no comment

if [ -z "$1" ] ; then # unset wine version
  export LD_LIBRARY_PATH=
  export WINESERVER=
  export WINELOADER=
  export WINEDLLPATH=
  export BINPATH=
else  # use wine version from path given by "$1"
  export LD_LIBRARY_PATH="$1"/lib:$LD_LIBRARY_PATH
  export WINSERVER="$1"/bin/wineserver
  export WINELOADER="$1"/bin/wine
  export WINEDLLPATH="$1"/lib/wine
  export BINPATH="$1"/bin/
fi

WINE=$BINPATH/wine
}


### functions for that are only in use with wine

check_prefix () {  # check if  $1 is a prefix
  if ! ( [ -d "${WINEPREFIX_PATH:-$HOME/.}/$1" ] && [ -e "${WINEPREFIX_PATH:-$HOME/.}/$1/system.reg" ] ); then
      return 1
  fi  
} 




set_wine_db () { # set wine debug
  if [ -z $WINEDEBUG ]; then 
    export WINEDEBUG=${WDEBUG:=fixme-all}
  fi
}



exec_exe () { # start wine with $exe
  if [ ! -z "$1" ]; then
    runed_exe="$1"
    shift
    ext=1
    while test "$ext" != ""
      do
	"${WINE:-wine}" $wine_args "$runed_exe" $@ ; return_stat=$?
	ext=
    done
    return $return_stat
  fi
}

prefix () { # set prefix var
    export WINEPREFIX=${1:-${PREFIX:-$HOME/.wine}}
}




### base functions 

exec_cmd () {
  #BIN=wineconsole
  "${WINE:-wine}" cmd.exe /c "$1"
}



if [ ! -z "$WINEPATH" ]; then
    check_wineserver || exit 1
    set_wine_ver "$WINEPATH"	
fi
default_win_arch=win32 # define the default wine architecture
err_input_messages="no options given run $appname -h for help, or -H for long help:wrong options or only prefix given run $appname -h for help, or -H for long help" # err messages for test_input
export WINE_PREFIXES="$WINEPREFIX_PATH" # for winetricks


#############################################



u_help () { # display short help
d_msg 'help' "`cat <<_HELP
Usage: $appname wineprefix command/file options
supported files: *.exe;*.bat;*.cmd;*.reg;*.dll

  syntax: $appname [prefix] [command/file] [options]

type $appname -H for long-help
_HELP`"
}

u_long_help () { # display long help
d_msg 'help' "\
Usage: $appname wineprefix command/file options 
supported files: *.exe;*.bat;*.cmd;*.reg;*.dll 

  syntax: $appname [options] [prefix] [command/file] [start taget options] 
  

general options:
  -g	--gui			enable gui output
  -h	--help			show help
  -H	--long-help		show this text, long help
  -V	--version		show version
	--revision		show revision
  -v	--verbose		be more verbose
	--debug			help us in debuging
  
options:
  -b	--binpath <binpath>	define in wich path $appname will search for wine and CO
  -r    -run-debug		don't set WINEDEBUG to ${default_w_db:='default $WINEDBUG not set'}  (\$default_w_db)
  -d 	--desktop    		start file/command in virtual desktop 
  -D 	--directory  		tell $appname to change directory to started file
  -p    --prefix     		replacement for prefix, $appname will ask for prefix is this option is given ( usefull to start Windows programms out of file manager)
  commands:
    winefile open winefilebrowser
    winecfg  open winecontrol
    appconf  control the software of the chosen prefix
    control  open control
    cmd      open winecommandline
    open     open prefix directory with xdg-open

  file specific  options:

    *.bat/*.cmd file:
      -w, --window open file in new window

    *.reg file:
      -i import regefile
      -e export the given part of registry to file
	 syntax for export to regfile :
	 $appname [prefix] [regfilename.reg] -e [regpath]

ENVIRONMENT
    
    WINEPATH		
      set path where $appname searchs for wine
    WINEPREFIX_PATH
      path where $appname searchs for wineprefixs, default is \$HOME
"
}


# tools

u_create_prefix () {
  
    if d_msg f prefix "prefix $1 don't exist, create it?" ; then  # if prefix doesn't exist create one yes or no?
      if [ `uname -m` = x86_64 ]; then
	 buttons='win32:1,win64:0'
	 case $DMSG_GUI in
	    1|true)	input=`d_msg i 'prefix select' "Which Windows architecture the prefix should support please enter win64(64bits) or win32(32bits), default $default_win_arch"`;;
	    *)
	      echo "Which Windows architecture the prefix should support please enter win64(64bits) or win32(32bits), default $default_win_arch"
	      read input
	      ;;
	 esac
	 case  "$input" in
	   win32) export WINEARCH=win32 ;;
	   win64) export WINEARCH=win64 ;;
	   *) d_msg 'prefix arch' "$default_win_arch used" ; export WINEARCH=$default_win_arch ;;
	 esac
      fi
    else
      return 1
    fi

}

skip_run() {
  while [ ! $# -eq 0 ] ; do
    run_int=`echo $run_int | sed "s/$1//"`
    shift
  done
}

add_run() {
  while [ $# -gt 0 ] ; do
    run_int=$run_int:$1
    shift
  done
}


# main function

main () {
    old_ifs=$IFS
    IFS=:
    for run_i in $run_int ; do
	IFS=$old_ifs
	$run_i
	IFS=:
    done
    IFS=$old_ifs
    unset IFS
    if check_prefix "$1" || u_create_prefix "$1"   ; then
	prefix ${WINEPREFIX_PATH:-$HOME/.}/"$1"
    else
	return 1
    fi

    runed_exe="$2"
    shift 2 # shift $+1 to remove $1 from $@ that arguments go collected to started program # maybe replace file type detection by extension with detection through mime-type
    case "$runed_exe" in # detect wich file or options given
	*.EXE|*.exe|*.bin)	"${WINE:-wine}"$cmd $wine_args "$runed_exe" $@ ;; # exec executable file
	*.dll|*.ax) "$BINPATH"regsvr32 $@ ;;
	*.bat|*.BAT]|*.cmd|*.CMD) # exec bat/cmd file
           case $runed_exe in
	       -w|--window)  "$BINPATH"wineconsole --backend=user cmd.exe $1 $2  $3 ;; # if option -w (--window) start file in new window
	       *)  "${WINE:-wine}" cmd.exe /c "$runed_exe $@" ;;
	   esac
	   ;;
	   *.reg) # import regfile into prefix
	   case $1 in
	       -e)  "$BINPATH"regedit /e "$runed_exe" $2 ;;
	       -i)  "$BINPATH"regedit "$runed_exe"    ;;
	       *)  d_msg ! faile 'no option for import(-i) or export (-e) given' ;;
	   esac
	   ;;
	   *.msi) wine "$BINPATH"msiexec.exe /i "$runed_exe" "$@" ;;
# built in commands
  ##############
       appconf|uninstaller)  "$BINPATH"wine $wine_args uninstaller.exe $@ ;;
       cmd)      "${WINE:-wine}" $wine_args cmd.exe "$@" ;; #console --backend=curses
       control)  "${WINE:-wine}" $wine_args control.exe $@ ;;
       open)  
       if echo  "$1" | grep -q '[Aa-Zz]:' ; then
	   xdg-open "$( winepath -u "$1" )"
       else
	   xdg-open "$WINEPREFIX"/"$1"  
       fi
       ;;
       *) sh -c  "exec "$runed_exe" $@"  ;; #we use exec cause its safer cause "$runed_exe" cant be a internal function
  esac
}

if [ ! -t 1 ] ; then # test if is usenew runned outside from terminal and use DMSG_GUI=true to get gui output from d_msg if outsite of terminal
  DMSG_GUI=1
fi

if [ ! $# = 0  ] ; then
  ext=1
  while test "$ext" != "" # main loop
    do	
	posixly=$POSIXLY_CORRECT
	export POSIXLY_CORRECT=1 # set POSIXLY_CORRECT to true cause we want that getopt stops after first non option  input to prevent that it parses the arguments of $runed_exe
	run_int=set_wine_db
	u_optspec=rb:dphHvVg #-: # short options
	u_optspec_long=run-debug,binpath:,desktop,prefix,help,long-help,verbose,debug,revision,gui,version # long options
	PROCESSED_OPTSPEC=$( getopt -o $u_optspec --long $u_optspec_long \
	-n $appname  -- "$@")  || d_msg ! error  "$( read_farray "$err_input_messages" 2 )" || exit 1 # parsed optspec
	eval set -- "$PROCESSED_OPTSPEC"
	export POSIXLY_CORRECT=$posixly
	unset posixly
	while [ ! $# = 0 ] ; do # TODO: improve this with getopt
	  case "$1" in
	    -h|--help) u_help ; shift ;;
	    --long-help|-H|-HL) u_long_help ; shift ;;
	    --debug) 
	      set -o verbose
	      set -o xtrace
	      shift
	      continue
	      ;;
	    -v|--verbose) set -o verbose  ; shift ; continue ;;
	    --revision)	d_msg revision "$USE_REV" ; shift ;;
	    -V|--version) 	d_msg version "$USE_VER" ; shift ;;
	    -g|--gui) 	DMSG_GUI=1 ; shift ; continue ;; # display msg in gui	  	
		-r|--run-debug) skip_run set_wine_db ; shift ;; 
		-b|--binpath) 	import libuse/wine_misc ; set_wine_ver "$2" ; shift 2 ;;  # set which wine version usenew should use
		-d|--desktop) 	argument_d=$(echo eval echo \$$#);  wine_args="explorer /desktop=$( basename $( $argument_d ) | sed 's/.exe//g'),800x600" ; unset argument_d ;shift ;; 
		-p|--prefix) 
		  argument_p=$( echo eval echo \$$# )
		  argument_p=$( $argument_p )
		  file=`basename $argument_p`
		  case $DMSG_GUI in
		    1|true) prefix="`d_msg i 'enter prefix' "Please enter prefix to start $file"`" ;;
		    *)
 		      echo "Please enter prefix to start $file"
 		      read prefix
 		      test ! -z $prefix 
 		      ;;
		  esac  || exit 1 
		  unset argument_p file
		  shift
		;;
		--) shift; break ;; # if [ $1 =  -- ] ; then no more options in input  
	  esac
	done
	if [ $# = 0 ] ; then 
	  true
	elif test_input $@ $prefix  ; then
	  IFS=$old_ifs
	  main $prefix $@
	  # 	    old_ifs=$IFS
	  # 	    IFS=:
	  # 	    for run_i in $run_int_p ; do
	  # 	      IFS=$old_ifs
	  # 	      $run_i
	  # 	      IFS=:
	  #	    done
	else
	  false
	fi
	error_status=$? 
    ext=
  done
else
  echo $(read_farray "$err_input_messages" 1) 
  false
fi
exit $error_status

Linux odin 3.13.1-pf #1 SMP PREEMPT Wed Mar 5 21:47:28 CET 2014 x86_64 GNU/Linux

Offline

#2141 2013-06-25 20:01:29

defer
Member
From: Finland
Registered: 2013-06-25
Posts: 46
Website

Re: Post your handy self made command line utilities

How about script to download every script in this thread as a separate file?

Heres small function :

sysinfo () {
echo "DMESG :"
dmesg | tail -n10

echo "SYSLOG :"
tail -n10 /var/log/messages

echo "NETSTAT :"
netstat -tnp | grep ESTABLISHED
}

Offline

#2142 2013-07-02 07:58:15

kokoko3k
Member
Registered: 2008-11-14
Posts: 1,471

Re: Post your handy self made command line utilities

I wanted my preferred scan program to popup on scanner connection so i wrote this rule:

# /etc/udev/rules.d/90-scanner-gbscan.rules 
SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{libsane_matched}="yes" , ACTION=="add", RUN+="/root/scripts/scanner.udev.autoconnect.sh "

Three problem raised:
1) understand who is logged to X

#/root/scripts/Xuser.print.sh
#Print the first user on display ":0"
#!/bin/bash
echo `w |grep "\:0 "|cut -f 1 -d " "|head -n 1`

2) set his environment:

#!/bin/bash
#/root/scripts/environment.user.print.sh
#Print the current environment variables exported by user (the first argument)
user=$1
userprocs=`ps -u $user |cut -f 1 -d " " |sort -u |grep -e [0..9]`
tmpfile=/var/tmp/$$_$$_$$.tmp
for proc in $userprocs ; do
    strings /proc/$proc/environ >> $tmpfile
done
cat $tmpfile | sort -u |grep \=
rm $tmpfile

3)Pass the environment to sudo

#!/bin/bash
Xuser=$(/root/scripts/Xuser.print.sh)
XuserEnv=$(/root/scripts/environment.user.print.sh $Xuser)
export $XuserEnv &>/dev/null
export DISPLAY=":0.0"
sudo -E -H -u $Xuser /usr/bin/gbscan

Now as i plug my scanner, gbscan pops up with the correct style smile


-EDIT-
Ouch, it gets killed after 120secs, and specifying OPTIONS+="event_timeout=3600" has no effect sad
https://bbs.archlinux.org/viewtopic.php … 3#p1295193

Last edited by kokoko3k (2013-07-02 08:42:24)

Offline

#2143 2013-07-02 09:54:59

ibrunton
Member
From: Canada
Registered: 2011-05-05
Posts: 270

Re: Post your handy self made command line utilities

Sometimes I think of a command I'll need later, so I wrote this function for a one-time alias.  I use it in zsh, but I think I originally wrote it when I was using bash.

function tempalias() {
	alias_name=$1
	shift
	alias $alias_name="$@ && unalias $alias_name"
}

Offline

#2144 2013-07-04 09:33:32

rasch
Member
Registered: 2012-02-23
Posts: 4

Re: Post your handy self made command line utilities

Here is a ruby script that I use as a cron job to send me an email when the packages on my computer have changed so that I always have an up to date list of packages (that are not in base). It also checks for AUR packages, your external IP Address, and current cron jobs. 

#!/usr/bin/env ruby

require "open-uri"
require "net/smtp"
require "time"


# Path to file containing @secret variable, change as needed.
# the file secret.rb should contain one line (and of course `chmod 600 secret.rb`)
# @secret = your_smtp_password
require "#{Dir.home}/path/to/secret"  # leave off the .rb extension :)


# Settings (change)
@log_directory = "#{Dir.home}/.logs"
@send_to = "example@somedomain.com"
@smtp_usr = "example@gmail.com"
@smtp_pwd = @secret


# Create log directory if it doesn't exist.
unless File.exists? @log_directory
  Dir.mkdir @log_directory
end


# Check current ip address with icanhazip.com and writes to a log file if it
# has changed. Also sends an email if changed since last log.
#
# Returns external ip address.
def get_external_ip
  current_ip = "#{@log_directory}/current_ip"
  ip = open("http://icanhazip.com").read
  f = File.exists?(current_ip) ? File.open(current_ip).read : ""
  if ip != f
    File.open(current_ip, 'w') { |f| f.write(ip) }
    send_email('IP address changed', ip)
  end
  ip
end


# Check current cron jobs and write to a log file if they have changed. Also
# sends an email if changed since last log.
#
# Returns output of running `crontab -l`.
def get_active_crons
  cronlist = "#{@log_directory}/cronlist"
  crons = `crontab -l`
  c = File.exists?(cronlist) ? File.open(cronlist).read : ""
  if crons != c
    File.open(cronlist, 'w') { |f| f.write(crons) }
    send_email('cron jobs changed', crons)
  end
  crons
end


# Check currently installed packages on arch linux and write to a log file if
# they have changed. Also sends an email if changed since last log.
#
# Returns Array of all installed packages from pacman and aur.
def get_installed_pkgs
  aur_log = "#{@log_directory}/aurpkglist"
  pkg_log = "#{@log_directory}/pkglist"
  all_installed = `pacman -Qeq`.strip.split "\n"
  aur_installed = `pacman -Qqm`.strip.split "\n"
  base_installed = `pacman -Qgq base base-devel`.strip.split "\n"
  aurs = aur_installed.map! { |x| x unless base_installed.include? x }
  aurs.compact!
  pacmans = all_installed.map! do |x|
    x unless (base_installed + aur_installed).include? x
  end
  pacmans.compact!
  a = File.exists?(aur_log) ? File.open(aur_log).read : ""
  if aurs.join("\n") != a
    File.open(aur_log, 'w') { |f| f.write(aurs.join("\n")) }
    send_email('Arch AUR packages updated', aurs.join("\n"))
  end
  b = File.exists?(pkg_log) ? File.open(pkg_log).read : ""
  if pacmans.join("\n") != b
    File.open(pkg_log, 'w') { |f| f.write(pacmans.join("\n")) }
    send_email('Arch packages updated', pacmans.join("\n"))
  end
  all_packages = pacmans + aurs
end


# Send email using google's smtp servers. Requires @smtp_usr, @smtp_pwd, and
# @send_to variables to be set at beginning of this script.
#
# subj - The String to serve as the subject of the email.
# msj  - The String containing the message of the email.
#
# Returns nothing.
def send_email(subj, msg)
  mail_content = <<END_OF_CONTENT
From: #{@smtp_usr}
To: #{@send_to}
Subject: #{subj}
Date: #{Time.now.rfc2822}

#{msg}
END_OF_CONTENT
  smtp = Net::SMTP.new("smtp.gmail.com",587)
  smtp.enable_starttls
  smtp.start("smtp.gmail.com", @smtp_usr, @smtp_pwd, :login) do
    smtp.send_message(mail_content, @smtp_usr, @send_to)
  end
end


# Lets run 'em all. Set up a cron job.
if __FILE__ == $0
  get_external_ip
  get_active_crons
  get_installed_pkgs
end

Offline

#2145 2013-07-16 19:53:31

Archer777
Member
Registered: 2012-06-12
Posts: 13

Re: Post your handy self made command line utilities

Rename multiple files with vi(m).

Update:
* Added topological sort before renaming, so it's possible to rename a ➜ b, b ➜ c.
* Ability to handle rename cycles: a ➜ b, b ➜ c, c ➜ a.
* List contents of cwd if no file names are given on command line.

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Std;
use File::Temp qw( tempfile );
use File::Basename qw( basename dirname );
use File::Spec::Functions qw( no_upwards );

$Getopt::Std::STANDARD_HELP_VERSION = 1;
my %opts;

# callback for Getopt::Std
sub VERSION_MESSAGE {
    my ($handle) = @_;
    print {$handle} "virename v0.2\n";
}

my $help_message = <<'EOF';
Usage:
 virename [OPTIONS] [file_names]

OPTIONS
 -s                act on symlink target (also update symlink)
 -v                be verbose
 --help            pirnt help and exit
 --version         version
EOF

# callback for Getopt::Std
sub HELP_MESSAGE {
    my ($handle) = @_;
    print {$handle} $help_message;
}

getopts 'vs', \%opts or die $help_message;

@ARGV or @ARGV = no_upwards( glob "* .*" );

my ( @old_names, %is_symlink );
if ( $opts{s} ) {

    # If a file is a symlink, we need to find the actual target
    # and put that into @old_names instead.
    for my $file_name ( sort @ARGV ) {
        if ( my $target = readlink $file_name ) {
            $is_symlink{$target} = $file_name;
            push @old_names, $target;
        }
        else { push @old_names, $file_name; }
    }
}
else { @old_names = sort @ARGV; }

@old_names or die "Nothing to rename!\n";

my @new_names;
{
    my ( $names_file_fh, $names_file ) = tempfile();

    # If file is a symlink print only basename of target
    print {$names_file_fh} join "\n", map {$is_symlink{$_} ? basename $_ : $_} @old_names;

    system("vim $names_file 2>/dev/null") == 0
      or system( "vi", $names_file ) == 0
      or die "Can't launch vim or vi\n";

    seek $names_file_fh, 0, 0;
    chomp( @new_names = <$names_file_fh> );

    unlink $names_file;

    # If new name is of a symlink replace it with a path to new name
    for ( 0 .. $#new_names ) {
        if ( $is_symlink{ $old_names[$_] } ) {
            $new_names[$_] = dirname( $old_names[$_] ) . q{/} . $new_names[$_];
        }
    }
}

@old_names == @new_names
  or die "Number of filenames changed. Did you deleted a line?\n";

my %new_name_of;
@new_name_of{@old_names} = @new_names;

# Removing unchanged names
delete $new_name_of{$_} for grep $_ eq $new_name_of{$_}, keys %new_name_of;

my ( $sorted_old_names, $cross_ref_names ) = topo_sort( \%new_name_of );

# Circular renaming
if ( %{$cross_ref_names} ) {
    print " Circular renaming...\n";

    $opts{v} = 1;

    my $rename_cycles = find_rename_cycles( %{$cross_ref_names} );
    for my $rename_cycle ( @{$rename_cycles} ) {

        # To break the renaming cycle we will rename the 1st_name of cycle
        # to tmp_name and rename the tmp_name to new_name at the end
        my $first_name = $rename_cycle->[0];
        my $tmp_name = tmp_name_for( $new_name_of{ $first_name } );
        push @{$rename_cycle}, $tmp_name;
        if ( $is_symlink{ $first_name } ) {
            $is_symlink{ $tmp_name } = $is_symlink{ $first_name };
        }

      RENAME:
      for my $old_name ( @{$rename_cycle} ) {
            my $new_name = do {
                if    ( $old_name eq $first_name ) { $tmp_name }
                elsif ( $old_name eq $tmp_name ) { $new_name_of{ $first_name } }
                else              { $new_name_of{$old_name} }
            };

            renamer( $old_name => $new_name ) or next RENAME;
        }
    }
}

# Normal renaming
if ( @{$sorted_old_names} ) {
    print "\n Normal renaming...\n" if %{$cross_ref_names};
  RENAME: for my $old_name ( @{$sorted_old_names} ) {
        my $new_name = $new_name_of{$old_name};

        renamer( $old_name => $new_name ) or next RENAME;
    }
}

#===  FUNCTION  ================================================================
#         NAME: renamer
#      PURPOSE: renaming and updating symlink
#   PARAMETERS: old_name => new_name
#      RETURNS: nothing
#===============================================================================
sub renamer {
    my ( $old_name, $new_name ) = @_;

    if ( -e $new_name ) {
        warn "failed to rename \"$old_name\" to \"$new_name\": file exists\n";
        return;
    }

    rename $old_name => $new_name or do {
        warn "failed to rename \"$old_name\" to \"$new_name\": $!\n";
        return;
    };

    if ( $is_symlink{$old_name} ) {
        my $symlink = $is_symlink{$old_name};

        # updating symlink
        unlink $symlink;
        symlink $new_name => $symlink
          or warn "symlink: $!\n";
        print "\"$symlink\": \"$old_name\" => \"$new_name\"\n"
          if $opts{v};
    }
    else { print "\"$old_name\" => \"$new_name\"\n" if $opts{v}; }

    return 1;
}    ## --- end sub renamer

#===  FUNCTION  ================================================================
#         NAME: topo_sort
#      PURPOSE: sort given names topologically so its possible to rename:
#               a -> b, b -> c
#   PARAMETERS: hash_ref (old_name => new_name)
#      RETURNS: * topologically sorted list of names as an array_ref
#               * circular renames as hash_ref (empty if no circles found)
#===============================================================================
sub topo_sort {
    my ($new_name_of) = @_;
    my %on;
    while ( my ( $old, $new ) = each %{$new_name_of} ) {
        $on{$old}{$new} = 1;
        $on{$new} ||= {};
    }

    my @sorted;
    while ( my @new = sort grep { !%{ $on{$_} } } keys %on ) {
        push @sorted, @new if @{$new_name_of}{@new};
        delete @on{@new};
        delete @{$_}{@new} for values %on;
    }

    %on = map { $_, $new_name_of->{$_} } keys %on;
    return ( \@sorted, \%on );
}    ## --- end sub topo_sort

#===  FUNCTION  ================================================================
#         NAME: find_rename_cycles
#      PURPOSE: find_circular renames ( a -> b, b -> c, c -> a )
#   PARAMETERS: hash (old_name => new_name)
#      RETURNS: topologically sorted array for every circle found as array of
#               arrays (empty if no circles found)
#===============================================================================
sub find_rename_cycles {
    my %new_name_of = @_;
    my @cycles;

    # We will follow the names in %new_name_of keeping track of 1st_name
    # ( a => b -> b => c ) until we get back to first name
    # ( a => b -> b => c -> c => a ) hence finding a renaming cycle
    while (%new_name_of) {
        my ( $old, $new ) = each %new_name_of;
        my @cycle = $old;

        while ( $old ne $new ) {
            push @cycle, $new;
            $new = $new_name_of{$new};
        }
        @cycle = reverse @cycle;
        push @cycles, \@cycle;
        delete @new_name_of{@cycle};
    }

    return \@cycles;
}    ## --- end sub find_rename_cycles

#===  FUNCTION  ================================================================
#         NAME: tmp_name_for
#      PURPOSE: generate tmp_file_name making sure it doesn't already exists
#   PARAMETERS: string
#      RETURNS: string
#===============================================================================
sub tmp_name_for {
    my ($name)   = @_;
    my $tmp_name = $name;
    my $counter  = 0;

    $tmp_name = $name . q{_} . ++$counter while -e $tmp_name;

    return $tmp_name;
}    ## --- end sub tmp_name_for
__END__

Last edited by Archer777 (2013-07-26 22:15:14)

Offline

#2146 2013-07-17 13:25:43

quigybo
Member
Registered: 2009-01-15
Posts: 220

Re: Post your handy self made command line utilities

@Archer777: check out `vidir` in the "moreutils" package.

Offline

#2147 2013-07-17 13:30:27

karol
Archivist
Registered: 2009-05-06
Posts: 25,427

Re: Post your handy self made command line utilities

@Archer777
https://bbs.archlinux.org/viewtopic.php?id=166600

I suggest renameutils: qmv ("quick move") program allows file names to be edited in a text editor.


I don't know if either vidir or qmv offer the same options as your script, but they're worth a look (if you haven't checked them already ;P ).

Offline

#2148 2013-07-17 19:31:14

Archer777
Member
Registered: 2012-06-12
Posts: 13

Re: Post your handy self made command line utilities

Thanks @quigybo and @karol. I didn't knew about those utilities.
'vidir' and 'qmv' both are very useful utilities although I couldn't find symlink processing (rename target and update symlink afterwards) in any of them.

Offline

#2149 2013-07-17 20:08:56

karol
Archivist
Registered: 2009-05-06
Posts: 25,427

Re: Post your handy self made command line utilities

Archer777 wrote:

I couldn't find symlink processing (rename target and update symlink afterwards) in any of them.

Symlink stuff was one thing that caught my eye in your script (I can't read perl ;P), that's why I wrote that little caveat at the end of my post.



I noticed that w/o '-v' I don't get some errors. When trying to rename 'foo' => 'bar' & 'bar' => 'baz' with the verbose switch I get

$ virename -v foo bar
'bar' already exists!
'bar' => 'baz'
$ ls
total 0
-rw-r--r-- 1 0 Jul 17 21:49 baz
-rw-r--r-- 1 0 Jul 17 21:49 foo

while w/o it

$ virename foo bar
$ ls
total 0
-rw-r--r-- 1 0 Jul 17 21:49 baz
-rw-r--r-- 1 0 Jul 17 21:49 foo

The effect is the same, but no error / warning without the '-v' switch.

Other errors, like

$ virename fo ba
failed to rename fo to foo: No such file or directory
failed to rename ba to bar: No such file or directory

are present with or without the '-v' switch.

Offline

#2150 2013-07-17 20:23:05

Archer777
Member
Registered: 2012-06-12
Posts: 13

Re: Post your handy self made command line utilities

karol wrote:

I noticed that w/o '-v' I don't get some errors.

Fixed.

Thanks for pointing that out.

Offline

Board footer

Powered by FluxBB