You are not logged in.
-snip-
Oh, so that's how it works.
Thanks for explaining!
If it ain't broke, you haven't tweaked it enough.
Offline
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
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
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
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
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
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
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
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
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
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)
Help me to improve ssh-rdp !
Retroarch User? Try my koko-aio shader !
Offline
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.
Offline
yep
Help me to improve ssh-rdp !
Retroarch User? Try my koko-aio shader !
Offline
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
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
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
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
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
-EDIT-
Ouch, it gets killed after 120secs, and specifying OPTIONS+="event_timeout=3600" has no effect
https://bbs.archlinux.org/viewtopic.php … 3#p1295193
Last edited by kokoko3k (2013-07-02 08:42:24)
Help me to improve ssh-rdp !
Retroarch User? Try my koko-aio shader !
Offline
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
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
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
@Archer777: check out `vidir` in the "moreutils" package.
Offline
@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
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
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
I noticed that w/o '-v' I don't get some errors.
Fixed.
Thanks for pointing that out.
Offline