# Useful scripts



## Dr_Phoenix (Dec 2, 2008)

Hi people!
Please, post here useful scripts which can help to do some useful or difficult operation on FreeBSD OS.

I will be the first:

Script which restarts the PPP daemon if connection is lost or daemon hung up.
The principe: ping remote ~100% uptime server to determine if Internet connection available.

*ppp_check.sh*


```
#!/usr/bin/perl

use Net::Ping;

$server_to_ping="ya.ru";


sub check_ping_server
{
$host_alive=1;
$ping=Net::Ping->new('icmp');
if( $ping->ping($_[0]) ) { $host_alive=1;} 
 else  {$host_alive=0;}
return $host_alive;
}



if(!check_ping_server($server_to_ping))
    { 
    system("killall ppp"); 
    system("sleep 2"); 
    # Start PPP ADSL connection
    system("/usr/sbin/ppp -quiet -ddial adsl");
    # Send the message to 
    system("echo PPP restarted by timeout...");
    }

exit;
```


Next one - Firebird databases backup script.
Assumed that catalogues have the next structure:

 - /Data
|   |  |
|   |  Database1 - DB1.FDB, DB2.FDB, ...
|   | 
|   |
|   Database2 - Data.FDB, Protocol.FDB, ...

The result of script work will be two archives in backup directory:
Database1-14-11-08_03_04.tar.gz
Database2-14-11-08_04_04.tar.gz

*db_backup.sh*


```
#!/bin/sh
#----------------- DB Backup Script -------------------
#------------- by Dr_Phoenix Lutsk 2007 ---------------

# mount backup volume if needed
#mkdir /mnt/temp
mount /dev/ad2s1d  /mnt/DB_BACKUP
clear

#---------------- Configure section -------------------
# Path to bases
db_path="/Data"
# Path to Backup directory			
backup_path="/mnt/DB_BACKUP"  
 Set path to GBAK  
gbak_path="/usr/local/bin/gbak" #
# Set date format to be attached to file name
current_date=`date "+%d-%m-%y_%H_%M"` 
# Enable Logging to console 1-yes/0-no
enable_verbose=1                 
#------------------------------------------------------

# Creating backup directory if not exist
if [ ! -d $backup_path ]; then
    mkdir $backup_path
fi

# Print short info about system
if [ $enable_verbose -gt 0 ]; then
    host_name=`uname -i -m -s`
    echo " ----> $host_name "
    echo " ----> ${current_date} "
fi

# Begin main cycle of backuping :)
for i in `ls $db_path`
 do
    if [ -d $db_path/$i ]; then
    for n in `ls $db_path/$i/`
	do

	    if [ -f $db_path/$i/$n ]; then
		if [ $enable_verbose -gt 0 ]; then
		    echo "Backuping file : < $n >"
		    echo "File Full Path : $db_path/$i/$n"
		fi
		# check if backup dir exist
		if [ ! -d $backup_path/$i ]; then
		    mkdir $backup_path/$i
		fi
		# backuping current database file
		$gbak_path -USER SYSDBA -PASS masterkey -b $db_path/$i/$n $backup_path/$i/$n.GBK  -V -IG  -Y $backup_path/$i/$n.log

	    fi
	done

    fi

 # Creating GZIPped tar archive of current bases directory
 if [ $enable_verbose -gt 0 ]; then
 echo "----> GZipping Databases in $i ..."
 fi
 tar -czf $backup_path/$i-$current_date.tar.gz $backup_path/$i/*

 # Clearing DB directory...
 if [ $enable_verbose -gt 0 ]; then
 echo "----> Clearing DB directory $i ..."
 fi
 rm $backup_path/$i/*

 done
```


----------



## voice (Dec 2, 2008)

*Dr_Phoenix*, maybe it is better to add next line


> system("killall -9 ppp");


after


> system("killall ppp");


in ppp_check.sh script?
I think in this case You have more chance to kill ppp process.


----------



## graudeejs (Dec 2, 2008)

I use this script on file tree, that was copied from MSDOSFS or CD9660.
After copying files are marked executable. Also there are destop.ini and Thumbs.db files. Removing them by hand on large file trees is pain.

It also replaces most problematic characters, like spaces..., but not all (this can be easily adopted)

so here is my sollution:
rmwin****.sh (mod, modify name if you want, but that's original script name)

```
#!/bin/sh

rmWin____FileNames() {
  for fileName in $1/*; do
    newFileName=$(echo "$fileName" | tr ' []'\' '_-__')

    if [ "$fileName" != "$newFileName" ]; then
      mv -f "$fileName" "$newFileName"
    fi

    if [ -d "$newFileName" ]; then
      chmod u+wrx "$newFileName"
      rmWin____FileNames "$newFileName"
    else
      chmod uog-x,u+rw "$newFileName"
    fi

  done
}

if [ -d "$1" ]; then
  dir="$1"
else
  dir=`pwd`
fi

find "$dir" -name Thumbs.db -delete
find "$dir" -name "Desktop.ini" -delete

rmWin____FileNames "$dir"
echo "Win**** is removed!!!"
exit 0
```

I use this script a lot

P.S. i censored it 

EDIT:
http://aldis.git.bsdroot.lv/rmwinshit/


----------



## sverreh (Dec 2, 2008)

Here is a very simple little script that I use to reduce the size of pictures. Quite useful when you need to send a lot of large pictures by E-mail.


```
#! /bin/sh

# Convert JPG and PNG images to another quality.
# Used to reduce image size. (Useful for E-mail.)
# Requires convert (part of the ImageMagick port)

if [ $# -lt 2 ]
then
    echo "Usage: <quality (0 - 100)> <filenames>"
    exit
fi
q=$1
shift
for arg
do
    convert -quality "$q" "$arg" "small_""$arg"
done
```


----------



## kamikaze (Dec 2, 2008)

I collect my useful scripts in the sysutils/bsdadminscripts port:



			
				sysutils/bsdadminscripts/pkg-descr said:
			
		

> This is a collection of administration scripts. At the moment it
> consists of a script to control rc.d scripts at runtime, a
> script that runs common make targets on batches of ports, scripts to set
> variables for make jobs (like portconf, but with more possibilities).
> And scripts to check for broken packages and missing libraries.



Another script I find useful does automounting without HAL.


			
				sysutils/automounter/pkg-descr said:
			
		

> A script to dynamically configure amd and populate /media with appropriate
> links, when USB mass storage devices appear. It relies on geom labels, hence
> it only works for properly labeled devices.
> 
> ...



The following is my automounter.conf file.

```
ntfs=ntfs-3g
ntfs_options=rw,noatime,gid=5,umask=113,dmask=002,locale=en_GB.UTF-8
#ntfs_options=ro,force,noatime,gid=5,umask=113,dmask=002,locale=en_GB.UTF-8
msdosfs_options=$mount_options,-L=en_GB.UTF-8,-m660,-M770
ufs_options=rw,noatime
blacklist_devs="acd*"
blacklist_nodes="ufs/2*"
geli=1
evil_fuse=1
```

Of course all these ports come with extensive manual page documentation.


----------



## Dara (Dec 10, 2008)

Small script to clean out old amavisd-new stuff if it dosent do a good job by itselft..


mailclean.sh

```
#!/usr/local/bin/bash
#set -x  #Debug
#
#Script to clean  out old junk mail
#
#find $f/cur -type f -mtime +5 -exec rm '{}' '+'
#
MHOME=/var/amavisd/tmp
MDIRS=`/bin/ls -l /var/amavisd/tmp |/usr/bin/awk '{ print  $9 }'`
DATE=`date "+%Y-%m-%d %H:%M:%S"`

#First do amavisd/tmp files
cd /var/amavisd/tmp
for f in `/bin/ls -l /var/amavisd/tmp |/usr/bin/awk '{ print  $9 }'`
do
        find $f -type f -mtime +3d -exec rm {} \;
        echo "Tmp_files - $DATE - Cleaned $f" >> /var/log/mailclean.log
done

#Then do amavisd/tmp folders
cd /var/amavisd/tmp
for j in `/bin/ls -l /var/amavisd/tmp |/usr/bin/awk '{ print  $9 }'`
do
        find $j -type d -name 'amavis-20??????T*' -prune -mtime +1 -exec rm -rf {} \;
        echo "Tmp_folders - $DATE - Cleaned $f" >> /var/log/mailclean.log
done

#then do quarantine files
cd /var/amavisd/quarantine
for k in `/bin/ls -l /var/amavisd/quarantine |/usr/bin/awk '{ print  $9 }'`
do
        find $k -type f -mtime +3d -exec rm {} \;
        echo "Quarantine - $DATE - Cleaned $f" >> /var/log/mailclean.log
done

#
```
Not perfect in any way but maby somebody can have use for it..


----------



## bsddaemon (Dec 11, 2008)

The following script is written because I was having problem with database backup of a busy website in "live" mode. The database is archived, but corrupted. Once restored, there were something that didnt work normally.

Script to back up entire website in safe manner


----------



## harisman (Dec 11, 2008)

Since I don't trust pkg_delete -r for removing my packages ( some times ended with complete remove my whole gnome base by mistake) I use this simple script for manually uninstalling packages.

It stores a backup for each uninstalled package and displays the remaining installed dependencies.

Usage: pkg_remove.sh <package>

Please note that this script needs the /usr/ports/shells/bash and /usr/ports/ports-mgmt/pkg_cutleaves to operate.


```
#!/usr/local/bin/bash

before="/tmp/pkg_remove_before.tmp"
after="/tmp/pkg_remove_after.tmp"
package_backup="/tmp"

function check_error {
        error=$?
        if [ $error -gt 0 ] ; then
                echo "Fatal! problem found executing $1, exiting"
                exit 1
        fi
}

pkg_cutleaves -l > $before
check_error "pkg_cutleaves"

for a in $@
do 
        pkg_create -b `basename $a` $package_backup/`basename $a`
        check_error "pkg_create on $a"
        pkg_delete `basename $a`
        check_error "pkg_delete on $a"

done
pkg_cutleaves -l > $after
check_error "pkg_cutleaves"
diff $before $after | awk '
        BEGIN { print "####################################################"}
        /\</ {print "Unistalled: "$2}
        /\>/ {print "Remaining: "$2}
        END { print "####################################################"}
'
rm $before $after
```


----------



## bsddaemon (Dec 13, 2008)

Inspired by this thread, I just rewrite my "instead of *rm*, *mv* to trash" script


----------



## danger@ (Dec 13, 2008)

simple solution is to add the following line into the .cshrc:


```
alias rm 'mv -i \!* ~/.Trash'
```

and create ~/.Trash/ directory.


----------



## bsddaemon (Dec 13, 2008)

Nice tip, but with the file/dir which has the same name, the alias will overwrite the old one. Meanwhile, my script moves them to trash dir, but put them in the absolute and original path dir. Also, my script works regardless of which shell or OS you are using.

Not sure if it should be called "bug", but with this alias, you get error if you attempt to:

- Create, then delete file named *foo*.
- At any dir, create new dir named *foo*
- Error occurs when attempting delete dir *foo*

Still, it can handle file/dir name with white space, which my script doesnt support. Anyone know how to resolve this problem, please let me know


----------



## danger@ (Dec 13, 2008)

bsddaemon said:
			
		

> Nice tip, but with the file/dir which has the same name, the alias will overwrite the old one.



That's why there's mv -i 



			
				bsddaemon said:
			
		

> Not sure if it should be called "bug", but with this alias, you get error if you attempt to:
> 
> - Create, then delete file named *foo*.
> - At any dir, create new dir named *foo*
> - Error occurs when attempting delete dir *foo*



you probably didn't create ~/.Trash/ directory before using it, I forgot to mention it.


----------



## bsddaemon (Dec 13, 2008)

danger@ said:
			
		

> you probably didn't create ~/.Trash/ directory before using it, I forgot to mention it.



No, I created ".Trash" dir already. That was because in any dir, the system will not accept if there are a dir and file with the same name. E.g:


```
bsddaemon@workstation:~% touch foo                                                                                      19601
bsddaemon@workstation:~% mkdir foo                                                                                      19602
[1]bsddaemon@workstation:~% mkdir: foo: File exists
```


----------



## danger@ (Dec 13, 2008)

ah I see your point now  well we can call that bug...


----------



## graudeejs (Dec 21, 2008)

multimedia/playd

Here's my new script that i now use to control mplayer daemon.
I wrote this mainly because i wanted to improve control over
mplayer daemon.
For many things i control mplayer in daemon mode with fvwm menu.

one of most usefull things is, it can play files in directories recursively.
also it can be used to play playlist that was made last time, when you used it

this can easely be used from console as well.
give it a try, maybe you'll like it


P.S. i didn't wrote entire script, because it's almost 200 lines long, and I'll probably improve it sooner or later 

EDIT:
git repo:
http://aldis.git.bsdroot.lv/playd.sh/


----------



## graudeejs (Dec 27, 2008)

I've updated playd.sh script
I will continue to update it
you can get it from my git repo homepage
http://hg.bsdroot.lv/pub/aldis/playd.sh/
i will keep version on page up to date 

Now i use this script all the time as well


----------



## kamikaze (Dec 27, 2008)

I have this script which I use for creating start scripts for wine programs. It handles the mounting of ISO images and has some hooks to include own code.

```
#!/bin/sh
#
# winexec
#
# This script handles running programs with wine that require images to be
# mounted. Simply populate the required variables and put
#
# . winexec
#
# at the end of your script to run a program.
#
# version 1.1

# User line breaks as delimiters.
IFS='
'

# Set default settings.
{
	# The script name, by default taken from the filename.
	: ${name="$(echo "$0" | grep -Eo '[^/]+$')"}

	# Name wine binary.
	: ${wine_suffix=""}			# Run a different wine binary.
	: ${wine_bin="wine"}			# The wine binary.

	# Set wine directory.

	: ${wine_dir="$HOME/.wine"}		# Configuration folder.

	# Set logfile.
	: ${wine_log="$wine_dir/log.$name"}	# Name of the logfile

	# Set available actions.
	: ${exec_default="run"}			# The command that is used
						# when no command is given.
	: ${exec_actions="showlog mount umount"}# Other available commands.

	# Set command functions.
	: ${run_cmd="winexec_run"}
	: ${run_pre_cmd=""}
	: ${run_after_cmd=""}
	: ${mount_cmd="winexec_mount"}
	: ${mount_pre_cmd=""}
	: ${mount_after_cmd=""}
	: ${umount_cmd="winexec_umount"}
	: ${umount_pre_cmd=""}
	: ${umount_after_cmd=""}
	: ${showlog_cmd="winexec_showlog"}
	: ${test_cmd="winexec_test"}
	: ${cleanup_cmd="winexec_cleanup"}

	# Mount settings.
	: ${mount_images=""}			# A newline separated list
						# of images.
	: ${mount_nodes=""}			# Set this if you want
						# device links to /dev.
	: ${mount_devices="$(printf 'd\ne\nf\ng\nh\ni\nj\nk\nl')"}
						# List of permitted dos devices.
	: ${mount_type="cd9660"}		# The image format.
	: ${mounted_file="mounted.$name"}	# Remember mounted devices.
	: ${loaded_file="loaded.$name"}		# Remember loaded images.

	# Run settings.
	: ${run_binary=""}			# The name of the binary to run.
	: ${run_folder=""}			# The folder from where to run.
	: ${run_parameters=""}			# Parameters for the program.

	# X settings to restore if changed.
	: ${x_get_res_cmd="xrandr | grep \* | grep -Eo '+[0-9]+x[0-9]+'"}
	: ${x_res=$(eval "$x_get_res_cmd")} 
	: ${x_set_res_cmd="xrandr -s $x_res"}
	: ${x_refresh_cmd="xgamma -g 1; xrefresh"}
}

# Mounts the images given in 'mount_isos'.
winexec_mount() {
	eval "$mount_pre_cmd"

	for image in $mount_images; {
		echo "Loading image '$image'."
		image=$(mdconfig -a -t vnode -f "$image")
		echo "$image" >> "$wine_dir/$loaded_file"

		for device in $mount_devices; {
			device_dir="$wine_dir/dosdevices/$device:"
			if [ ! -L "$device_dir" -a ! -e "$device_dir" ]; then
				echo "Creating device '$device:'."
				if [ "$mount_nodes" ]; then
					ln -s "/dev/$image" "$device_dir:"
				fi
				mkdir "$device_dir"
				mount -r -t $mount_type "/dev/$image" "$device_dir"
				echo "$device" >> "$wine_dir/$mounted_file"
				break
			fi
		}
	}

	eval "$mount_after_cmd"
}

# Unmount images.
winexec_umount() {
	eval "$umount_pre_cmd"

	for device in $(cat "$wine_dir/$mounted_file" 2> /dev/null); {
		echo "Destroying device '$device:'."
		device_dir="$wine_dir/dosdevices/$device:"
		umount -f "$device_dir"
		rmdir "$device_dir" > /dev/null 2>&1
		rm "$device_dir:" > /dev/null 2>&1
	}
	rm "$wine_dir/$mounted_file" > /dev/null 2>&1

	for image in $(cat "$wine_dir/$loaded_file" 2> /dev/null); {
		echo "Destroying image node '$image'."
		mdconfig -d -u "$image"
	}
	rm "$wine_dir/$loaded_file" > /dev/null 2>&1

	eval "$umount_after_cmd"
}

# Show the logfile.
winexec_showlog() {
	cat "$wine_log"
}

# Test weather all required settings are set.
winexec_test() {
}

# Cleanup the environment.
winexec_cleanup() {
	# Check screnn resolution.
	if [ "$(eval "$x_get_res_cmd")" != "$x_res" ]; then
		eval "$x_set_res_cmd"
	fi

	# A little screen refresh never hurts.
	eval "$x_refresh_cmd"
}

# Run the given binary.
winexec_run() {
	eval "$test_cmd"
	eval "$mount_cmd"

	eval "$run_pre_cmd"

	echo "Running '$run_binary' with '$wine_bin$wine_suffix'."
	cd "$run_folder" && $wine_bin$wine_suffix "$run_binary" $run_parameters > "$wine_log" 2>&1

	eval "$run_after_cmd"

	eval "$cleanup_cmd"
	eval "$umount_cmd"
}

# Get the given command.
command=run
if [ $1 ]; then
	command=$1
fi

# Run the requested action.
for action in $exec_default $exec_actions; {
	if [ "$command" = "$action" ]; then
		eval $"${action}_cmd"
		exit 0
	fi
}

# This happens when a wrong parameter is supplied.
exit 1
```

This is an example for running starcraft:
	
	



```
#!/bin/sh

wine_suffix="-kthread"
mount_images="/mnt/msdos/vault/images/starcraft.iso
/mnt/msdos/vault/images/broodwar.iso"
run_binary="starcraft.exe"
run_folder="/mnt/msdos/software/games/rts/Starcraft"

. winexec
```


----------



## milosz (Dec 30, 2008)

I have a script that I used on FreeBSD 5 (2005/2006) at home, it was unused and not updated since then. 

It's a startup script used to keep network connection using usb adsl modem (speedtouch as I remember). It can also update .Xauthority file and reconnect... 

Maybe someone find some parts of it useful.


```
#!/bin/sh
#
# Plik: neo
#
# Info:
#  Skrypt startowy  (rc) poÅ‚Ä…czenia dla uÅ¼ytkownikÃ³w Neostrady.
#
# Parametry:
#  start            - poÅ‚Ä…cz siÄ™
#  restart          - restart poÅ‚Ä…czenia (cron)
#  beonline         - stara siÄ™ zapewniÄ‡ nieprzerwane poÅ‚Ä…czenie (cron)
#  stop             - zatrzymaj poÅ‚Ä…czenie
#
# Zmienne:  
#  modem_driver     - okreÅ›la poÅ‚oÅ¼enie firmware'u
#  ppp_flags        - parametry polecenia ppp
#  modem_run_flags  - parametry polecenia modem_run
#  ...
#
# Konfiguracja:
#  echo 'neo_enable="yes"' >> /etc/rc.conf
#  echo 'modem_driver="/etc/ppp/st330"' >> /etc/rc.conf 
#
# Konfiguracja cron'a:
# */5     *       *       *       *       root    /etc/rc.d/neo beonline
#
# Komentarz: 
#  Paremetry "start" oraz "stop" sÅ‚uÅ¼Ä… do rozpoczÄ™cia i zakoÅ„czenia poÅ‚aczenia.
#  Parametr restart przeznaczony jest do okresowego restartowania poÅ‚aczenia
#  uÅ¼ywajÄ…c cron'a (tylko z zaÅ‚oÅ¼enia), natomiast "beonline" sÅ‚uÅ¼y 
#  do restartowania poÅ‚Ä…czenia w przypadku jego utraty (ping), aktualizacji (ppp -ddial) 
#  i rÃ³wnieÅ¼ przeznaczony jest dla cron'a.
#
#  Konfiguracja wymaga skopiowania skrytpu do katalogu /etc/rc.d/ 
#  i zdefiniowania w pliku /etc/rc.conf zmiennych neo_enable oraz modem_driver.
#  
#  Dla skryptÃ³w startowych wymagajÄ…cych wczeÅ›niejszego poÅ‚Ä…czenia z sieciÄ…
#  naleÅ¼y zmodyfikowaÄ‡ reguÅ‚Ä™ REQUIRE dodajÄ…c parametr neo.
#
#
#
# PROVIDE: neo 
# REQUIRE: netif mountcrit local
# KEYWORD: nojail
#

. /etc/rc.subr

modem_driver=${modem_driver:-"/etc/ppp/st330"}

name="neo"
rcvar=`set_rcvar`
extra_commands="beonline" 
start_cmd="neo_start"
stop_cmd="neo_stop"
restart_cmd="neo_start"
beonline_cmd="neo_beonline"


#Polecenia
sh_command=${sh_command:-"/bin/sh"}
kill_command=${kill_command:-"/bin/kill"}
basename_command=${basename:-"/usr/bin/basename"}
xauth_command=${xauth_command:-"/usr/X11R6/bin/xauth"}
hostname_command=${hostname_command:-"/bin/hostname"}
domainname_command=${domainname_command:-"/bin/domainname"}
grep_command=${grep_command:-"/usr/bin/grep"}
ifconfig_command=${ifconfig_command:-"/sbin/ifconfig"}
awk_command=${awk_command:-"/usr/bin/awk"}
expr_command=${expr_command:-"/bin/expr"}
route_command=${route_command:-"/sbin/route"}
chown_command=${chown_command:-"/usr/sbin/chown"}
rm_command=${rm_command:-"/bin/rm"}

modem_run_command=${modem_run_command:-"/usr/sbin/modem_run"}
modem_run_flags=${modem_run_flags:-"-f"}

ppp_command=${ppp_command:-"/usr/sbin/ppp"}
ppp_flags=${ppp_flags:-"-quiet -ddial adsl"}
ppp_iface=${ppp_iface:-"tun0"}

ping_command=${ping_command:-"/sbin/ping"}
ping_flags=${ping_flags:-"-c1"}
ping_host=${ping_host:-"www.wp.pl"}

# Funkcja odpowiedzialna za restart firewall'a
# Wymaga dostrojenia do wÅ‚asnych potrzeb
neo_firewall(){
 $sh_command /etc/rc.firewall
}

# Funkcja odpowiedzialna za wczytanie firmware'u
neo_driver_load(){
 local modem_run_check

 modem_run_check=`check_process $modem_run_command`
 echo -n "Neo driver: "
 if [ -z "$modem_run_check" ]; then
  echo "loading"
  $modem_run_command $modem_run_flags $modem_driver >/dev/null
 else
  echo "already loaded"
 fi
}

# Funkcja sprawdzajÄ…ca, czy mamy poÅ‚Ä…czenie 
# sprawdzajÄ…c proces ppp
neo_connection_check(){
 local ppp_check
 
 ppp_check=`check_process $ppp_command`
 if [ -n "$ppp_check" ]; then
  echo "wait"
 fi
}

# Funkcja wywoÅ‚ujÄ…ca ppp
neo_connection_start(){
 $ppp_command $ppp_flags  2>/dev/null
}

# Funkcja zatrzymujÄ…ca ppp
neo_connection_stop(){
 local ppp_pid

 ppp_pid=`check_process $ppp_command`
 if [ -n "$ppp_pid" ]; then
  $kill_command $sig_stop $ppp_pid 2>/dev/null
  wait_for_pids $ppp_pid > /dev/null
 fi
}

# Funkcja pobierajÄ…ca adres ip
# Zwraca pusty string w przypadku niepowodzenia
neo_ip_get(){
 local ip="";
 local ppp_loop=1
 while [ -z "$ip" ] && [ "$ppp_loop" -le 12 ]; do
         sleep 4
         ip=`$ifconfig_command $ppp_iface | $grep_command netmask | $awk_command '/inet/ {print $2}'`
  ppp_loop=`$expr_command $ppp_loop \+ 1`
 done

 if [ "$ppp_loop" -eq "13" ]; then
  echo ""
  exit 1
 fi
 echo $ip
}

# Funkcja odpowiedzialna za czynnoÅ›ci po wykonaniu poÅ‚Ä…czenia
# Wymaga dostrojenia do wÅ‚asnych potrzeb
neo_postconfigure(){

 # Pobierz adres IP
 local ip=""
 local hostname=""
 local name_stat=""
 
 ip=`neo_ip_get`

 while [ -z "$ip" ]; do
  echo "Error"
  sleep 10
  exit 1
 done

 echo "IP: " $ip

 # Firewall
 echo "Firewall: configuring"
 neo_firewall 2> /dev/null

 # Pobranie nowej nazwy hosta oraz wywoÅ‚anie poleceÅ„
 # hostname, domainname
 hostname=""
 while [ -z "$hostname" ]; do
         hostname=`$route_command get $ip | $awk_command  '/route/ {print $3}'`
        
         if [ -n $hostname ]; then       
                 name_stat=`echo $hostname | $grep_command "tpnet.pl"`
                 if [ -z "$name_stat" ]; then
                         hostname=${hostname}.neoplus.adsl.tpnet.pl
                 fi
         else
                 sleep 2
         fi
 done

 echo "Hostname: " $hostname

 $hostname_command $hostname
 $domainname_command $hostname

 # Restart okreÅ›lonych usÅ‚ug po zmianie adresu IP
 #if [ -n "$ppp_restarted" ]; then
 #fi

 # X'y + xauth
 # Aktualizacja .Xauthority
 local xauth_file=/home/milosz/.Xauthority

 local mcookie=`dd if=/dev/urandom bs=16 count=1 2>/dev/null | hexdump -e \\"%08x\\"`
 $rm_command $xauth_file
 $xauth_command -f $xauth_file add $hostname:0 MIT-MAGIC_COOKIE-1 $mcookie 2>/dev/null
 $xauth_command -f $xauth_file add $hostname/unix:0 MIT-MAGIC-COOKIE-1 $mcookie 2>/dev/null

 $chown_command milosz:milosz $xauth_file
}

# Funkcja oficjalnie rozpoczynajÄ…ca poÅ‚Ä…czenie
neo_start()
{
 local ppp_loop=1
 local ppp_check=""
 local ip=""

 if [ -f "$modem_driver" ]; then
  neo_driver_load
  ppp_check=`neo_connection_check`

  echo -n "Connection: "
  
  if [ -n "$ppp_check" ]; then
   echo "restarting"
   neo_connection_stop
   ppp_restarted=1
   while [ "$ppp_check" = "wait" ]; do 
    if [ "$ppp_loop" -eq "13" ]; then
     echo "Error: IP address not assigned"
     sleep 10
     exit 1
    fi
    sleep 3
    ppp_check=`neo_connection_check`
    ppp_loop=`$expr_command $ppp_loop \+ 1`
   done
  else
   echo "starting"
  fi
  neo_connection_start
  ip=`neo_ip_get`
  echo $ip > /var/run/neo_ip
  neo_postconfigure
 fi 
}

# Funkcja oficjalnie zatrzymujÄ…ca poÅ‚Ä…czenie
neo_stop(){
 echo "Connection: stopped"
 neo_connection_stop 2>/dev/null
}

# Funkcja sprawdzajÄ…ca stan poÅ‚Ä…czenia (ping)
neo_ping_check(){
 local ping_check
 ping_check=`$ping_command $ping_flags ${ping_host} 2>/dev/null | $grep_command "1 packets"` 2>/dev/null
 echo $ping_check
}

# Funkcja odpowiedzialna za wznawianie utraconego poÅ‚Ä…czenia
neo_beonline(){
 local ping_check=""
 local ip=""
 local neo_ip
 ping_check=`neo_ping_check` > /dev/null
 if [ -z "$ping_check" ]; then
  echo "Connection lost!"
  neo_start
 else
  ip=`neo_ip_get`
  if [ -f /var/run/neo_ip ] && [ -n `cat /var/run/neo_ip` ]; then
   neo_ip=`cat /var/run/neo_ip`
   if [ "$ip" !=  "$neo_ip" ]; then
    echo $ip > /var/run/neo_ip
    ppp_restarted=1
    neo_postconfigure
   fi
  else
   neo_start
  fi
  
 fi
}

load_rc_config $name
run_rc_command "$1"
```


----------



## estrabd (Jan 5, 2009)

This is a script I wrote to take care of the arduous task of updating the ssh key of a single machine on some the machines listed in the variable, *HOSTS* below. Comments and suggestions are welcome.


```
#!bin/sh

HOSTS="host1 host2 host3"

KEYFILE=id_rsa # careful, change to not overwrite default!
PRVKEYFILE=~/.ssh/${KEYFILE}
PUBKEYFILE=${PRVKEYFILE}.pub
TMPKEY=${KEYFILE}.tmp

ssh-keygen -b 2048 -t rsa -f $PRVKEYFILE

for HOST in $HOSTS; do
  echo $HOST ###
  scp ${PUBKEYFILE} ${HOST}:~/${TMPKEY} && echo OK && \
    ssh ${HOST} "cat ${TMPKEY} >> ~/.ssh/authorized_keys && rm ~/${TMPKEY}" && echo OK
done
```

Also, the vee blogger thing (see sig) is really just a sh script. I use it as a blog tool when I feel the urge, but more often than not I use it in batch mode (via cron) to maintain a web log of various system processes. Comments and suggestions are welcome about that, too.


----------



## graudeejs (Jan 14, 2009)

Here's script i'm working on, for burning CD's
http://killasmurf86.lv/data/download/burn.sh.bz2
It's still incomplete, and probably buggy.
I will be updating it....

It can burn DVD's, CD's, make Disk Images

It has fallowing dependencies:
mkisofs
growisofs
mplayer


EDIT:
I almost completely rewrote my script

EDIT:
it's not available any more


----------



## vermaden (Jan 14, 2009)

killasmurf86 said:
			
		

> Here's script i'm working on, for burning CD's
> http://killasmurf86.lv/data/download/burn.sh.bz2
> It's still incomplete, and probably buggy.
> I will be updating it....
> ...


You may check mine scripts/wrapers for burning CD/DVD: 
http://daemonforums.org/showthread.php?t=126


----------



## chalbersma (Jan 14, 2009)

*Torsmo's .torsmo_ip script*

If you use Torsmo and have used any of tight configuration scripts lying around the web you've probably relized that the standard .torsmo_ip script used doesn't give you and ip address.  Well there are many reasons for this but this will let you get it.


```
#!/bin/sh
# Torsmo IP config file
# Replace "dc0" with the name of your network connection
# chris@beastie.westminster-mo.edu
/sbin/ifconfig [red]dc0[/red] | awk '/inet / {split($2, x, / /); printf "%s", x[1]; exit;}'
```

Drop me an email if it doesn't work


----------



## vermaden (Jan 14, 2009)

*Universal screenshot*

A script that will make a screenshot @ FreeBSD/OpenSolaris/Linux OS:


```
#! /bin/sh

DATE=$( date +%Y.%m.%d_%H:%M:%S )
APPS="scrot imlib2_grab import"
DIR=~/gfx/screenshots
FILE=${DIR}/vermaden_${DATE}.png

[ ${#} -ne 0 ] && FILE="${@}"

for I in ${APPS}
do
  which ${I} 1> /dev/null 2> /dev/null && {
    SHOT=${I}
    break
  }
done

[ -z $SHOT ] && {
  echo "ER: no screenshot application in \$PATH"
  echo "IN: provide one of [ scrot | import | imlib2_grab ] into your \$PATH"
  exit 1
}

mkdir -p ${DIR} || {
  echo "ER: cannot create ${DIR} dir"
  exit 1
}

case ${SHOT} in
  (import) import -display :0.0 -window root ${FILE} ;;
  (*)      ${SHOT} ${FILE} ;;
esac
```


----------



## paulfrottawa (Feb 21, 2009)

It would be useful to have a copy button to lift some scripts. Just a thought


----------



## graudeejs (Feb 21, 2009)

paulfrottawa said:
			
		

> It would be useful to have a copy button to lift some scripts. Just a thought


open editor, select text in forum with mouse, push midle mouse button in text editor

or select text in forum Ctrl+C open editor, Ctrl+V

save script.... that's it


----------



## ivand58 (Mar 19, 2009)

Some backup tools have problems with long names. So we have to check the length of the *path + file name*. This can be done with:
 [cmd=]find . -type f -exec sh -c 'echo -n \"$@\"\, ; echo -n $@ | wc -c' x {} \; | awk -F \, '{ printf "%s %s", $2, $1 "\n" }' | sort |tail[/cmd]


----------



## t4z3v4r3d (Mar 26, 2009)

Some of people want to ping some hosts and find which host is up 


```
#! /usr/local/bin/bash
clear

da="`date`"
range=${1}
ttl=${2}
count=${3}
sub=$4
us="`id -u`"
if [ $us != "0" ];then
echo "SORRY U MUST BE ROOT"
exit
fi

alive="/usr/home/t4z3v4r3d/alive.txt"
if [ "${#}" != 4 ] ; then
echo "EXAMPLE ${0} 127.0.0.1 2 1"
echo -e "TARGET IP Count   TTL  Subrange \n 127.0.0  1    1      254"
exit 0
fi

if test -f $alive  ;then
echo -en "\033[1;32mFile OK  Startting with PID:$$ \033[0;0m"
else
echo "$alive Not found creating it"
touch $alive
fi

#############################
## Chekc state for nom of tarets
for ((i=1 ; i < 100000 ; i++));do
if [ "`cat $alive | grep "\["$i"\]"`" != "" ];then
let "i=i+1"

else
let "i=$i-1"
echo "starting target nom form $i "
break
fi
done

#############################
line=2
ln=2
sb=0
pinger(){
while [ "$sb" -le "$sub" ];do
        for ((counter=1 ; counter < 254 ;counter++));do
                if [ "`ping -c $count -t $ttl $range.$sb.$counter | grep icmp_seq= `" != "" ];then
                         let "j=j+1"
                         let "ln=$j+2"
                         let "line=$j+2"
                         let "k=$i+$j-1"
                         let "a=a+1"
                         echo -e "\033[1;37m\033[3;2f[+]$range.$sb.$counter                     Alive   [\033[1;32m$a\033[1;37m]\033[0;0m"
                         target[$k]=$range.$sb.$counter  # >> $alive
                else
                         let "d=d+1"
                         echo -e "\033[4;2f\033[1;31m[+]$range.$sb.$counter                     Dead    [$d]\033[0;0m"
                fi
        done
let "sb=$sb+1"
done
        echo -e "\033[4;1f...............................................................\033[0;0m"

}
## END SUB RANGE AND IP
chmod 666 $alive
pinger
let "l=$j+0"
if [ "$l" != "0" ];then
case $j in
        0) some="No  Target"
        ;;
        1) some=" $j Taregt"
        ;;
        *) some=" $j Targets  "
        ;;
esac

echo "Scanning done and $some founded"

som1=0
while [ "$som1" -le "$j" ];do
echo -e "\033[1;37m${target[$som1]}\033[0;0m"
let "som1=som1+1"
done

else
echo "Cant find any target or pinging faild !"
fi
```


----------



## graudeejs (Apr 8, 2009)

Here's script that i use to backup my FreeBSD to flash 
you must have root permissions to run it.
you need flash or other unmounted drive with ufs on it labeled backup

to backup run
*sudo backup.sh --backup all*
or
*sudo backup.sh --backup usr var*
your partitions must be labeled, because this script uses only labels created with *newfs -L label*

Using partition labels has a lot of advantages.

it will save compressed dump images to /tmp, so it must be big enough.

for me it takes up to 1.8GB per download.
It compresses on the fly

modify DEFAULT_BAK_FS to match out ufs labels



```
#!/bin/sh


DEFAULT_BAK_FS='root var home www usr'


if [ "$USER" = 'root' ]; then
	if [ -c /dev/ufs/backup ]; then

		if [ "$1" = '--backup' ]; then
			echo '*** starting backup ***'
			echo

			mkdir "/tmp/$(basename $0).$$"

			echo '*** saving kernel configuration ***'
			cat /usr/src/sys/i386/conf/killabsd | bzip2 > "/tmp/$(basename $0).$$/killabsd.bz2"

			if [ "$2" = 'all' ]; then
				for i in $DEFAULT_BAK_FS; do
					echo "*** dumping $i ***"
					dump -0Laf - "/dev/ufs/$i" | gzip > "/tmp/$(basename $0).$$/$i.dump.gz"
					shift
				done
			else
				while [ $2 ]; do
					echo "*** dumping $2 ***"
					dump -0Laf - "/dev/ufs/$2" | gzip > "/tmp/$(basename $0).$$/$2.dump.gz"
					shift
				done
			fi

			bakDate="$(date '+%Y-%m-%d')"

			echo '*** Mounting ks86backup ***'
			mount -o noatime /dev/ufs/backup /mnt

			echo '*** Saving Backups ***'
			if [ ! -d '/mnt/bak' ]; then mkdir '/mnt/bak'; fi
		
			if [ ! -d "/mnt/bak/$bakDate" ]; then rm -Rf "/mnt/bak/$bakDate"; fi
			mkdir "/mnt/bak/$bakDate"
		
			cp "/tmp/$(basename $0).$$/"* "/mnt/bak/$bakDate/"

			umount /mnt
			echo '*** ks86backup unmounted ***'

			echo '*** cleaning tmp ***'
			rm -Rf "/tmp/$(basename $0).$$"
			echo "*** backup $bakDate compleate ***"
			exit 0
		elif [ "$1" = '--restore' ]; then
			echo 'not implemented yet'
			exit 1
		else
			echo 'Err: unknown command'
			exit 1
		fi
	else
		echo "Err: backup drive ain't plugged"
		exit 1
	fi
else
	echo "Err: you're not root"
	exit 1
fi

echo "Err: you shouldn't naturally see this. A bug is somwhere."
exit 1
```


----------



## t4z3v4r3d (Apr 10, 2009)

*Extended storage Automatic Mounter*


```
#!/usr/local/bin/bash
clear
echo "Looking for mountable devices"
if  [ "`ls -c /dev/da* | grep s`" = "" ] ;then
echo -e "\033[1;31mNo such device for mounting\033[0;0m"
exit
fi

for (( count =0; count <5 ;count++ ));do
        for ((counter=1 ;counter <7;counter++ ));do
                if [ -c "/dev/da""$count"s"$counter" ];then
                        if [ ! -d /mnt/usb${count}-$counter ];then
                        echo "/mnt/usb${count}-$counter  NOT EXITS CREATING IT ..."
                        mkdir /mnt/usb${count}-$counter
                        chmod -R 777 /mnt/usb${count}-$counter
                        chmod 666 /dev/da${count}s${counter}
                        fi
                        mount_msdosfs /dev/da${count}s${counter} /mnt/usb${count}-${counter}
                fi
        done
done
echo "_________________________________________"
echo
        mount -p -w | grep da
echo "_________________________________________"
```

Only run this script and you can mount your storage with write permission in X.


----------



## graudeejs (Apr 10, 2009)

t4z3v4r3d said:
			
		

> ```
> #!/usr/local/bin/bash
> clear
> echo "Looking for mountable devices"
> ...



add to /etc/devfs.rules

```
[localrules=10]
add path 'da*' mode 0660 group users
add path 'md*' mode 0660 group users
```

add to /etc/devfs.conf

```
own acd0 root:users
perm acd0 0660

own cd0 root:users
perm cd0 0660

own mdctl root:users
perm mdctl 0660

own pass0 root:users
perm pass0 0660
```

add to /etc/rc.conf

```
devfs_system_ruleset="localrules"
```


do steps described above and you won't need to chmod devices anymore
also to mount msdosfs all you need to do, is create dir (for example ~/mnt)
and 
*mount -t msdosfs /dev/da0 ~/mnt*
and you can read/write etc


p.s.
for more info about cd's/dvd's check
http://forums.freebsd.org/showthread.php?t=1195


----------



## t4z3v4r3d (Apr 12, 2009)

Ok thank you but iwrote this scripts 2 years ago for training 
But thank you again . And i wanna lowest changes !.
Sorry for poor english


----------



## MG (Aug 16, 2009)

Not really useful, but nostalgic:


```
#!/bin/sh

# Edit UNIX text files with old MSDOS editor
# Requires: - Dosbox installed
#           - DOS binary EDIT.COM
#           - X 

EDITOR_BIN=/usr/files/EDIT.COM             # fix your path
CURDIR=$(pwd)

mkdir -p /tmp/dostmp
ln -s $EDITOR_BIN /tmp/dostmp/edit.com

if [ $1 ];
then
  cp $1 /tmp/dostmp/EDIT.TMP
  cd /tmp/dostmp
  dosbox -c "@mount c ." -c "@c:" -c "@c:\edit c:\EDIT.TMP" -c "@exit"
  cd $CURDIR
  (cat /tmp/dostmp/EDIT.TMP | tr -d '\015') > $1    #remove carriage returns
  rm /tmp/dostmp/EDIT.TMP                                                           
else
  cd /tmp/dostmp
  dosbox -c "@mount c ." -c "@c:" -c "@c:\edit" -c "@exit"
fi

cd /tmp/dostmp
rm ./edit.com

# in case more files are saved:
# (these will get XXXXXXXX.XXX DOS-filenames)
for REST in *;
do
   if [ -f $REST ];
   then
     (cat $REST | tr -d '\015') > $CURDIR/$REST
   fi
done

rm -rf /tmp/dostmp
```

Use at own risk :beergrin


----------



## copypaiste (Aug 17, 2009)

If you're an owner of a digital camera and like to fiddle with those JPEG files in your console as often as I do  then this lil' piece of a shell-script of mine would be useful for you.
It provides batch changing the date/time of given JPEG files according to their EXIF values. 



```
#!/bin/sh
#
# redate.sh
#----------------------------------------------------------------------
#  This script changes modification and access time of the files
#  in the current folder, according to the EXIF metadata found inside.
#
#  No changes will be made in case no EXIF data could be found.
#
#  Also it drops file permissions to 0640 mode
#
#  Please be sure to have graphics/exiftags port installed before use.
#---------------------------------------------------------------------

exts="*.jpg *.jpeg *.JPG *.JPEG"
mask="0640"
exifcmd="/usr/local/bin/exiftags"
msg="Searching for ${exts} files..."




# Check for exiftags binary presense:
/usr/bin/which exiftags

if [ $? -ne 0  ]
then
    printf "\n -> graphics/exiftags is not found in ${exifcmd}\n\n"
    exit 1
else
    printf "\n -> found exiftags binary  (Ok!)"
fi




if [ $1 ]
then
    exts=$1
    msg="Searching for ${exts} files..."
fi


files=0
changed=0
failed=0

printf "\n${msg}\n"

for n in `ls ${exts} 2> /dev/null`

do

files=$((${files}+1))

    exifd=`${exifcmd} ${n} 2> /dev/null | grep Created`


    if [ "${exifd}" ]
    then

        exd=`echo ${exifd} | cut -d ' ' -f 3`

        y=`echo ${exd} | cut -d ':' -f 1`
        m=`echo ${exd} | cut -d ':' -f 2`
        d=`echo ${exd} | cut -d ':' -f 3`

        t=`echo ${exifd} | cut -d ' ' -f 4`

        hr=`echo ${t} | cut -d ':' -f 1`
        min=`echo ${t} | cut -d ':' -f 2`
        sec=`echo ${t} | cut -d ':' -f 3`

        printf "\n=> File: ${n} -> Exif Date: ${y}:${m}:${d} - Time: ${hr}:${min}:${sec} -> Set."

        touchd="${y}${m}${d}${hr}${min}.${sec}"

        touch -c -t ${touchd} ${n}

                if [ $? -eq 0 ]
                then
                        chmod ${mask} ${n}
                        changed=$((${changed}+1))
                fi
    else
        {
           printf "\n=> (!) File: ${n} -> No EXIF data ->  Skipped."

           failed=`echo "${failed}+1" | bc`
        }
    fi

done

echo
echo " -----------------------------------"
printf "Files processed:       $files \n"
printf "Successfully set:      $changed \n"
printf "Failed:                $failed \n"
echo

exit 0
```


----------



## vermaden (Aug 18, 2009)

*mount(8) ISO image on FreeBSD/Solaris/Linux*

[cmd=]*usage:* loop.sh image.iso /mnt/point[/cmd]


```
#! /bin/sh

[ ${#} -ne 2 ] && {
  echo "usage: $( basename ${0} ) image.iso /mnt/point"
  exit 1
}

__absolute() {
  if [ -f /${1} ]
  then
    echo "${1}"
  else
    echo "$( pwd )/${1}"
  fi
}

case $( uname ) in
  (FreeBSD)
    NODE=$( mdconfig -a -t vnode -f "${1}" )
    mount -t cd9660 /dev/${NODE} "${2}"
    ;;

  (SunOS)
    FILE=$(  __absolute "${1}" )
    POINT=$( __absolute "${2}" )
    lofiadm -d "${FILE}" 1> /dev/null
    NODE=$( lofiadm -a "${FILE}" )
    mount -F hsfs -o ro ${NODE} "${POINT}"
    ;;

  (Linux)
    mount -o loop "${1}" "${2}"
    ;;

  (*)
    echo "supported systems: FreeBSD Solaris Linux"
    exit 1
    ;;
esac
```


----------



## graudeejs (Sep 1, 2009)

```
#!/bin/sh
# Copyright (c) 2009, Aldis Berjoza <killasmurf86@gmail.com>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
#   copyright notice, this list of conditions and the following disclaimer
#   in the documentation and/or other materials provided with the
#   distribution.
# * Neither the name of the  nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# This scrip will create 'wlist' file, that will contain IP of all
#   ftp servers found in ports collection
# You may use this script to generate ftp server whitlist for pf
#
# http://killasmurf86.blogspot.com

find /usr/ports -name Makefile > /tmp/.ftp_list_1
find /usr/ports/Mk -name bsd.*.mk >> /tmp/.ftp_list_1

for i in `cat /tmp/.ftp_list_1`; do 
	grep -e 'ftp://' $i >> /tmp/.ftp_list_2
done

sed 's/#.*$//g' /tmp/.ftp_list_2 | sed 's/^.*ftp:\/\///' | sed 's/\/.*$//' | sort | uniq - /tmp/.ftp_list_3

grep -E -e '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' /tmp/.ftp_list_3 > /tmp/.ftp_list_4

for i in `cat /tmp/.ftp_list_3`; do
	dig +short "$i" | grep -E -e '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' >> /tmp/.ftp_list_4
done

sort /tmp/.ftp_list_4 | uniq - wlist
rm -f /tmp/.ftp_list_[1234]

exit
```

Here's script, I just wrote to generate ftp server white list used in ports.
I use generated list in my pf configuration, to enable ftp downloads

EDIT:
latest version can be downloaded from
http://aldis.git.bsdroot.lv/ftpwlist/


----------



## DutchDaemon (Sep 1, 2009)

*portupdater script*

*Note: if you're using PKGNG and the pkg tools, use the revised portupdater*: viewtopic.php?f=35&t=737&p=260551&hilit=portupdater#p260551

\My 'portupdater' script for daily use. Requires ports-mgmt/portmaster and ports-mgmt/portaudit.

The script can be run from cron, which will invoke portsnap with a random sleep period of 0-60 minutes and does not require any intervention. It mails a summary to e.g. root.

It can also be run from the command-line when an extra argument is supplied (e.g. [cmd=]portupdater yes[/cmd] or [cmd=]portupdater now[/cmd]). This will make it run immediately, and with some extra functions that may require interaction.

The script will only update/maintain the ports tree and show a summary, it will not update ports. The ports that need updating are printed, of course.

The script can be made to work with ports-mgmt/portupgrade by just replacing the applicable commands. In fact, this script used to be portupgrade-based before I switched to portmaster.

```
#!/bin/sh
hostname=$(hostname)
date=$(/bin/date)

echo "
Updating portaudit first.
"
/usr/local/etc/periodic/security/410.portaudit

echo "
Portupdater for ${hostname} started at ${date}


========== Fetching latest ports snapshot from server. ==================
"

if [ $# -lt 1 ]
then
portvar="cron"
else
portvar="fetch"
fi

/usr/sbin/portsnap ${portvar} || exit 1

echo "
========== Updating ports tree with new snapshot. =======================
"
/usr/sbin/portsnap update || exit 1

echo "
============ Cleaning out all obsolete distfiles. =======================
"
/usr/local/sbin/portmaster -y --clean-distfiles || exit 1

if [ ${portvar} = "fetch" ]
then
echo "
Ah, you're actually here. Good.

Running some (possibly) interactive stuff.
"
/bin/sleep 5

echo "
============ Cleaning out stale ports. ==================================
"
/usr/local/sbin/portmaster -s || exit 1
echo "
============ Checking port dependencies. ================================
"
/usr/local/sbin/portmaster --check-depends || exit 1
echo "
============ Cleaning up /var/db/ports. =================================
"
/usr/local/sbin/portmaster --check-port-dbdir || exit 1
fi

echo "
=================== See which ports need updating. ======================
"
/usr/sbin/pkg_version -IvL '=' || exit 1

echo "
================= Warnings from /usr/ports/UPDATING. ====================
"
weekago=$( /bin/date -v-1w +%Y%m%d )
lastpkg=$( ls -D %Y%m%d -ltr /var/db/pkg | /usr/bin/tail -n1 | /usr/bin/tr -s " " "\t" | /usr/bin/cut -f 6 )
if [ ${weekago} -lt ${lastpkg} ]
 then usedate=${weekago}
 else usedate=${lastpkg}
fi
/usr/sbin/pkg_updating -d ${usedate}
echo "
See /usr/ports/UPDATING for further details.

========== Portupdater done. ============================================
"
```


----------



## bigearsbilly (Sep 28, 2009)

how a bout this? convert code to a pretty html page
if you have gvim with syntax highlighting


```
gvim  -c TOhtml -c w -c q -c q  source_file
```


----------



## bigearsbilly (Sep 28, 2009)

killasmurf...

dontcha just hate it when your license is longer than your script?


I remember the good old days when one would put useful info at the
top of source files!


----------



## graudeejs (Sep 28, 2009)

Well AT&T used to put their license on *false* program

And all it did was *return 1*


If you want I can make special edition for you.... I can make that script take more lines than license


----------



## t4z3v4r3d (Sep 29, 2009)

Hi 
and a script for cvsup ...


```
#!/usr/local/bin/bash
clear
echo -e "\033[1;30mGetting fastest server adress\n\033[1;33mPlease wait  ...\033[0;0m"
fastest_cvsup -c all >> /tmp/1
tail -n 3 /tmp/1 > /tmp/fs_cvs
echo -e "\033[1;32mGetting informations Done ...\nStarting update\033[0;0m"

cat << config > /root/stable_supfile.txt
###################################################################
##### Generated by $USER @ `date` ######
###################################################################
$(cat /tmp/fs_cvs  | while read line ;do echo *default host=$(echo $line | awk {' print $3 '}); done)
*default base=/var/db
*default prefix=/usr
*default release=cvs tag=RELENG_$(uname -r | cut -d . -f 1)_$(uname -r | cut -d . -f2 | cut -d - -f 1)
*default delete use-rel-suffix
*default compress
src-all
config
cvsup -g -L 2 /root/stable_supfile.txt
```


----------



## nimnod (Oct 14, 2009)

If you want to block known spam sources on your MX right at the firewall, not even bothering you MTA to check the incoming IPs you can use this script to put together a list of IPs to block.

Watch out: The script reloads your pf rules.
You should put:

```
table <spam.zen>        persist file "/etc/spam.zen"
(...)

block quick inet from <spam.zen>
```
into your pf.conf for the whole thing to work.


```
#!/bin/sh

fetch -q -o /tmp/zendrop.data http://www.spamhaus.org/drop/drop.lasso

cat /tmp/zendrop.data | sed -e 's/;.*//' > /tmp/spam.zen
rm /tmp/zendrop.data
MD1=`md5 -q /tmp/spam.zen`
if [ -f /etc/spam.zen ]; then
    MD2=`md5 -q /etc/spam.zen`
else
    MD2="nof"
fi

echo $MD1 | grep "$MD2" > /dev/null
if [ $? -eq 1 ]; then
    echo "New file: /tmp/spam.zen"
    sleep .5
    more /tmp/spam.zen
    echo -n "Do you want to replace previous version of /etc/spam.zen ? yes/[no]: "
    read reload
    echo $reload | grep yes > /dev/null
    if [ $? -eq 0 ]; then
        # yes
        mv /tmp/spam.zen /etc/
        pfctl -qf /etc/pf.conf
        echo "Your ZENDROP list has been updated."
    else
        # no
        echo "Your ZENDROP list has not been updated."
    fi
else
    rm /tmp/spam.zen
    echo "Your ZENDROP list is up-to-date."
fi
```


----------



## t4z3v4r3d (Nov 3, 2009)

Hi there.
Anybody has script for network monitoring ?  such as BW monitor !


----------



## vermaden (Nov 3, 2009)

@t4z3v4r3d

Have you tried this:
`% systat -if 1`


----------



## t4z3v4r3d (Nov 3, 2009)

Thank you .
Not yet but ill try  .


----------



## anomie (Nov 3, 2009)

*Miscellaneous/simple utilities I put together*

*Save yourself from mistyping during jail creation*

Runs through the basic jail creation steps, as described in jail(8). The idea is it helps you avoid changing the path by mistake on one of the steps or doing something else silly. (Requires that you've built world on your base system first.) 


```
#!/bin/sh

#
# Very simple - feed it jpath and let it create / mount for you. 
#
_jpath=/home/jail/basicjail

myprompt() {

  echo "Step finished. Return code: ${_rc}"
  echo '<press enter>'
  read _foo

}

echo 'Creating jail path...'
mkdir -p ${_jpath}
_rc=${?} ; myprompt

echo 'Installing world to jail...'
cd /usr/src && make installworld DESTDIR=${_jpath}
_rc=${?} ; myprompt

echo 'Making distribution in jail...'
cd /usr/src && make distribution DESTDIR=${_jpath}
_rc=${?} ; myprompt

echo 'Mounting devfs for jail...'
mount_devfs devfs ${_jpath}/dev
_rc=${?} ; myprompt

exit 0
```

------------------------------

*Automating the aide HIDS*

Requires the security/aide and security/gnupg1 ports. After initializing (and signing!) your aide db, set up a root cronjob that runs this daily with the "check" argument. 


```
#!/bin/sh

### Variable assignments ### ---------------------------------------------------

PATH=/bin:/usr/bin:/usr/local/bin
DB=/var/db/aide/databases/aide.db

### Functions ### --------------------------------------------------------------

init_aide_db() { 

  aide -i

  if [ ${?} -ne 0 ] ; then 
    echo 'Initializing new db failed. Exiting now.'
    exit 1
  fi

  echo "Finished initializing db. When ready to implement and sign the db," 
  echo "please run: ${0} goprod"

}

implement_and_sign_db() {

  echo 'Moving newly initialized db to production db...'
  mv ${DB}.new ${DB}

  if [ ${?} -ne 0 ] ; then 
    echo 'Unable to copy new db to prod. Exiting now.'
    exit 1
  fi

  echo 'Signing db with GNUPG - password required...'
  gpg -u 'System Admin' --detach-sign ${DB}

}

run_aide_check() { 

  # check signature
  gpg --verify ${DB}.sig ${DB}

  if [ ${?} -ne 0 ] ; then 
    echo "Signature check against ${DB} failed!!!"
    exit 1
  fi
 

  aide -C

  if [ ${?} -ne 0 ] ; then 
    init_aide_db
  fi

}


### Main logic ### -------------------------------------------------------------

case "${1}" in

  'init'   ) init_aide_db ;;
  'goprod' ) implement_and_sign_db ;;
  'check'  ) run_aide_check ;;
  *        ) echo "Usage: ${0} (init|goprod|check)" ; exit 1 ;;

esac


exit 0
```

------------------------------

*See the most common squid proxy TCP denied hosts*

I like to check in every now and then on which hosts end users are trying to access (and getting denied). This provides a quick, sorted list. Obviously requires an actively used www/squid service. 


```
#!/bin/sh

# ----------------------------------------------
# Quick audit
# ----------------------------------------------

if [ ! -e "${1}" ] ; then
  echo "Usage: ${0} squid_access_log"
  exit 1
fi

_acheck=`echo ${1} | grep 'access.log'`

if [ -z "${_acheck}" ] ; then
  echo "${0}: my author told me to only scan 'access.log' type files"
  exit 1
fi

# ----------------------------------------------
# Variable assignment
# ----------------------------------------------

_squidlog=${1}
_of1=/tmp/tcp-squid-baz.txt
_of2=/tmp/tcp-squid-boo.txt


# ----------------------------------------------
# Main logic
# ----------------------------------------------

grep 'TCP_DENIED' ${_squidlog} | awk '{print $7}' | sort > ${_of1}

if [ ${?} -ne 0 ] ; then
  echo "${0}: error during grep"
  exit 1
fi

for I in `uniq ${_of1}` ; do 

  _cnt=`grep "${I}" ${_of1} | wc -l`
  echo "${_cnt} : ${I}" >> ${_of2}

done

#
# Display results
#
sort -nr ${_of2}

#
# Cleanup
#
rm -f ${_of1} ${_of2}

exit 0
```


----------



## idle (Nov 7, 2009)

Anti-ddos. Script for getting bots ips from httpd/nginx/etc log.

```
#!/usr/bin/perl -w

use strict;
use warnings;
use POSIX qw(strftime);

my $pattern = "\"GET \/ HTTP\/"; # request index page pattern
my $httpd_log = "/var/log/httpd-access.log"; # log file 
my $ok = "1000"; # allowed connections per ip for $check_period
my $check_period = 1; # check period in hours

my $date = strftime("%d/%b/%Y:%H", localtime(time-$check_period*3600)); # date minus $check_period hours
my (%ips, $ip, $start);

open (LOG, $httpd_log) or die $!;
while (<LOG>) {
        next unless m/$date/ || $start; # skipping old records
        $start=1;
        if (/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}).*$pattern/go) { # getting ips
                $ips{$1}++;
        }
}
close LOG;

foreach $ip (keys %ips) {
        if ($ips{$ip} >= $ok) { #
                next if $ip =~ /^127/; # skip local address
                print "$ip = $ips{$ip}\n"; next; # comment out this line if you want to modify firewall rules and uncomment one of the following
                #system("/sbin/pfctl -t bots -T add $ip"); # adding address to table <bots> 
                #system("/sbin/ipfw table 5 add $ip"); # adding address to table 5
                #system("/sbin/iptables -A INPUT -s $ip -j REJECT"); # adding denying rule
        }
}
```
The shortest way to generate the random password. The slowest, also. =)

```
egrep -aoim1 '[a-z0-9]{8,}' /dev/random
```


----------



## pat (Nov 8, 2009)

I have a patchset against /usr/src (mostly low priority PRs waiting for approval) arranged in an overlay. This little function takes care of applying the patches after an update of src:


```
overlay="/home/pat/Projects/patchset"
find "${overlay}/usr/src/" -type f | \
  while read patchfile; do \
    srcdir=$(dirname ${patchfile});
    srcdir=${srcdir##$overlay};
    cd ${srcdir} && sudo patch < ${patchfile};
done
```


----------



## MG (Nov 14, 2009)

```
#!/usr/local/bin/bash

# turns a text-file into keyboard-controlled menu (basic example)
# use <UP> and <DOWN> arrows to choose, <RETURN> to confirm, <ESC> to abort
# scrolling is nog supported yet, so the menu may not contain more lines than your terminal screen
 
if [ ! -f "$1" ]
then
  printf "need input file\n"
  exit
fi

OLDIFS=$IFS
NOCOLOR='\033[0m'
YELLOW='\033[1;33;40m'
CHOICE=1
LASTLINE=$(cat $1 | wc -l)
UP=$'\x1b[A'
DOWN=$'\x1b[B'
KEY=''
ASCII=""
ESC=""
END=0

function xy                                   # cursor positioning
{
  printf "\033[$2;$1f"
}

printf "\x1B[?25l"                            # hide terminal cursor
clear
cat $1

while [ $END = 0 ]
do
  xy 0 $CHOICE
  printf $YELLOW
  cat $1 | head -n $CHOICE | tail -n 1        # highlight current option
  IFS=''                                      # don't convert any read chars to whitespace
  read -s -n1 KEY                           
  IFS=$OLDIFS
  ASCII=$(printf "%d" "'$KEY'")               # store ascii value of key

  if [ "$ASCII" = "27" ]                      # function key processing
  then
    read -t0.1 -s -n2 ESC                     # store 2 more bytes containing the escape code
    xy 0 $CHOICE
    printf $NOCOLOR                           # remove highlighting
    cat $1 | head -n $CHOICE | tail -n 1

    if [ "$ESC" = "" ]                        # <ESC>
    then
      END=1
    else
      case $ESC in
        "[A")                                 # <UP>
          if [ $CHOICE = 1 ]
          then
            CHOICE=$LASTLINE
          else
            (( CHOICE-=1 ))
          fi
        ;;
        "[B")                                 # <DOWN>
          if [ $CHOICE = $LASTLINE ]
          then
            CHOICE=1
          else
            (( CHOICE+=1 ))
          fi
        ;;
      esac
    fi
  fi

  if [ $ASCII = 39 ]  && [ "$KEY" != "'" ]    # <RETURN> 
  then
    xy 0 $(( $LASTLINE + 2 ))
    printf "${NOCOLOR}you have chosen option $CHOICE:\n  $(cat $1 | head -n $CHOICE | tail -n 1)\n\n"
    END=1
  fi
```


----------



## MG (Nov 16, 2009)

```
#!/usr/local/bin/bash

if [ ! -f "$1" ]; then
  ( 
    (cat|cut -c5-) << EOF
    ...................................................................
     txt2menu.sh - turn a textfile into a keyboard-controlled menu
     1.1 (improved with pgup/pgdown and positioning/scrolling support)     
    ...................................................................
     start with:
       #txt2menu.sh [file] [#line] [#column] [#width] [#height]
         'line' and 'column' are the coords. of the upper left
          corner of the menu box
     run without parameters to view this example menu or use custom 
     file with default pos/size:
       #txt2menu.sh /etc/motd              
     or with filename and 4 pos/size parameters:
       #txt2menu.sh /etc/motd 10 10 50 20
    ...................................................................
     menu control keys: <UP>,<DOWN>,<PGUP>,<PGDOWN>,<ESCAPE>,<RETURN>
     exit code contains users choice or 0 when aborted
    ...................................................................
EOF
  ) > /tmp/demo.tmp
  printf "\n\n\n\n\n\n\n\n\n\n\n\n\n\nthis is freeware\nby MG\n" >> /tmp/demo.tmp
  CONTENT=/tmp/demo.tmp
else
  CONTENT=$1
fi

stty -echo

CLEAR=1  # set to 0 to run over existing terminal content.
HEIGHT=18
WIDTH=70
COLUMN=5
LINE=3
OLDIFS=$IFS
NOCOLOR='\033[0m'
YELLOW='\033[1;33;40m'
CHOICE=1
LASTLINE=$(cat $CONTENT | wc -l)
KEY=''
ASCII=""
ESC_CODE=""
END=0
STARTLINE=1

if [ "$2" != "" ]; then LINE=$2; fi
if [ "$3" != "" ]; then COLUMN=$3; fi
if [ "$4" != "" ]; then WIDTH=$4; fi
if [ "$5" != "" ]; then HEIGHT=$5; fi
if [ $LASTLINE -lt $HEIGHT ]; then HEIGHT=$LASTLINE; fi
if [ $CLEAR = 1 ]; then clear; fi
function cur_xy { 
  printf "\033[$2;$1f"
 }

function printmenu {
  sed -n "${STARTLINE},$((STARTLINE+HEIGHT-1))p" $1 | awk '{
    printf $0
    width="'"$WIDTH"'"-length($0);
    for (i=1; i<=int(width); i++) printf "^";
    print ""
  }' 
}

function out_at_xy { 
  (
    COL=$1
    LINE=$2
    shift
    shift
    while [ "$1" != "" ]; do
      printf "\033[$LINE;${COL}f"
      printf "$1"
      shift
      (( LINE+=1 ))
    done
  ) | tr '^' ' '
}

printf "\x1B[?25l"                            # hide cursor
out_at_xy $COLUMN $LINE $(printmenu $CONTENT | tr ' ' '^')

while [ $END = 0 ]; do
  printf $YELLOW
  cur_xy $COLUMN $((LINE+(CHOICE-STARTLINE)))
  ACTIVE_LINE=$(head -n$CHOICE $CONTENT | tail -n1)

  if [ "$ACTIVE_LINE" != "" ]; then 
    printf "$ACTIVE_LINE"
  else
    printf "o"
  fi
  IFS=''                                      
  read -s -n1 KEY                           
  IFS=$OLDIFS
  ASCII=$(printf "%d" "'$KEY'")               
  if [ "$ASCII" = "27" ]; then
    read -t0.0001 -s -n2 ESC_CODE
    printf $NOCOLOR                           
    cur_xy $COLUMN $((LINE+(CHOICE-STARTLINE)))

    if [ "$ACTIVE_LINE" != "" ]; then 
      printf "$ACTIVE_LINE"
    else
      printf "."
    fi

    if [ "$ESC_CODE" = "" ]; then                       # just <ESCAPE>
      END=1
    else
      case $ESC_CODE in
        "[A")                                      # <UP>
          (( CHOICE-=1 ))
          if [ $CHOICE -lt $STARTLINE ]; then
            if [ $CHOICE -lt 1 ]; then
              CHOICE=1
            else
              (( STARTLINE-=1 ))
              out_at_xy $COLUMN $LINE $(printmenu $CONTENT | tr ' ' '^')
            fi
          fi
        ;;
        "[B")                                      # <DOWN>
          (( CHOICE+=1 ))
          if [ $CHOICE -gt $LASTLINE ]; then
            CHOICE=$LASTLINE
          fi
          if [ $CHOICE -gt $((STARTLINE+HEIGHT-1)) ]; then
            (( STARTLINE+=1 ))
            out_at_xy $COLUMN $LINE $(printmenu $CONTENT | tr ' ' '^')
          fi
        ;;
        "[5"|"[I")                                 # <PGUP>
          (( CHOICE-=25 ))
          if [ $CHOICE -lt 1 ]; then
            CHOICE=1
          fi
          if [ $CHOICE -lt $STARTLINE ]; then
            STARTLINE=$CHOICE
            if [ $STARTLINE -lt 1 ]; then
              STARTLINE=1
            fi 
            out_at_xy $COLUMN $LINE $(printmenu $CONTENT | tr ' ' '^')
          fi
        ;;
        "[6"|"[G")                                 # <PGDOWN>
          (( CHOICE+=25 ))
          if [ $CHOICE -gt $LASTLINE ]; then
            CHOICE=$LASTLINE
          fi
          if [ $CHOICE -gt $((STARTLINE+HEIGHT-1)) ]; then
            STARTLINE=$((CHOICE-HEIGHT+1))
            out_at_xy $COLUMN $LINE $(printmenu $CONTENT | tr ' ' '^')
          fi
        ;;           
      esac
    fi
  fi
  if [ $ASCII = 39 ]  && [ "$KEY" != "'" ]; then   # <RETURN> 
    END=1
  fi
  read -t0.0001 -s -n10                            # don't remember more keys
done

printf "\x1B[?25h"                                 # unhide cursor
cur_xy 0 $(( $LINE+$HEIGHT+3 ))
stty echo

if [ $ASCII = 27 ]; then                           # final result message, delete this for further use
  printf "aborted.\n\n"
  CHOICE=0
else
  printf "${NOCOLOR}you have chosen option $CHOICE:\n$YELLOW$(cat $CONTENT | head -n $CHOICE | tail -n 1)$NOCOLOR\n\n"
fi

rm -rf /tmp/demo.tmp
exit $CHOICE
```


----------



## tangram (Nov 17, 2009)

pat said:
			
		

> I have a patchset against /usr/src (mostly low priority PRs waiting for approval) arranged in an overlay. This little function takes care of applying the patches after an update of src:
> 
> 
> ```
> ...



Do you use this as a standalone script that you run before rebuilding your kernel or world? Or do place this on make.conf?

I'm asking this because I also apply 2 patches to /usr/src and wanted to reapply the patches whenever I synchronize sources.


----------



## graudeejs (Nov 18, 2009)

```
#!/usr/bin/perl

use warnings;
use strict;
package wrapper;

if (defined $ARGV[0]) {
    $ARGV[0] =~ s/%([[:xdigit:]]{2})/pack('c', hex($1))/ge;
    if ($ARGV[0] =~ /^mailto:/) {
        my $email;
        my $subject;
        if ($ARGV[0] =~ /\?subject=.*/) {
            ($email, $subject) = $ARGV[0] =~ /^mailto:(.*)\?subject=(.*)/;
#            system("FvwmCommand \"Function Start_Mailer -s '$subject' -- '$email'\"");
            system("urxvtc -e mutt -s '$subject' -- '$email'");
        } else {
            ($email) = $ARGV[0] =~ /^mailto:(.*)/;
#            system("FvwmCommand \"Function Start_Mailer -- '$email'\"");
            system("urxvtc -e mutt -- '$email'");
        }
    }   
    elsif ($ARGV[0] =~ /^irc:\/\//) {
        my $addr;
        my $port;
        ($addr, $port) = $ARGV[0] =~ /^irc:\/\/(.*):\+(\d{1,5})/;
#        system("FvwmCommand 'Function Start_chat --connect=$addr --port=$port '");
        system("urxvtc -e irssi --connect=$addr --port=$port");
    }   
}   
exit;
```

Here's my little wrapper scipt I just wrote.
I commented out original lines that I use (fvwm & my config specific) and replaced them with more generic lines

replace urxvtc with any terminal that you use.

you can use this wrapper with firefox. In Application preferences, where you can select default apps for various things, for mailto: and irc: you can select this wrapper script.
It will launch mutt or irssi in virtual terminal on X, when you click on link (either mailto:... or irc:...)

I think it's pretty useful.
Of course you can customize to use it for other email/irc clients, and even extend it's usage to IM....

Hope you like it 


P.S.
Thanks to SirDice for this post

EDIT:
one more thing... Why I like it?
Because If I have to reply to some pr, I don't have to fill to: and subject lines....
subject line was pain for me with previous wrapper


EDIT:
fixed bug


----------



## pat (Nov 18, 2009)

tangram said:
			
		

> Do you use this as a standalone script that you run before rebuilding your kernel or world? Or do place this on make.conf?
> 
> I'm asking this because I also apply 2 patches to /usr/src and wanted to reapply the patches whenever I synchronize sources.



Actually it's only a shell function (minus the header).
I would just love to see something like this properly implemented in make.conf.


----------



## Ruler2112 (Nov 18, 2009)

I'm cross-posting to this thread, as the script I wrote may well be of use to somebody for a different purpose.  I intentionally wrote it to be as generic as possible.  Basically, it will update a local file to that of a network copy, based on whatever you set the variables to.  It'll also keep the n most recent backups of the file downloaded.  You can see it as part of the 'Emerging Threats' thread.


----------



## graudeejs (Nov 19, 2009)

fixed bug in script
http://forums.freebsd.org/showpost.php?p=49504&postcount=52


----------



## ohauer (Dec 26, 2009)

DutchDaemon said:
			
		

> /usr/sbin/portsnap update || exit 1
> cd /usr/ports || exit 1
> make fetchindex || exit 1



Is there a special reason for

```
cd /usr/ports || exit 1
make fetchindex || exit 1
```
since portsnap has already updated the index file to match the current portsnap.


----------



## DutchDaemon (Dec 26, 2009)

Yeah, that script has seen quite a few lifecycles and organic development (cvsup -> csup -> portsnap, portupgrade -> portmaster), and there may be some superfluous stuff in it. I'll give it a slight overhaul.


----------



## tuan (Dec 26, 2009)

Hello, 

I tried to reuse your script, and changed just one thing, but for some reason, my modification is not correct: I need to su on the remote machine before copying the keys, but when I enter the password for su, the remote machine does not accept it. Does anyone have an idea by chance ? 

Your original script was : 


```
#!bin/sh

HOSTS="host1 host2 host3"

KEYFILE=id_rsa # careful, change to not overwrite default!
PRVKEYFILE=~/.ssh/${KEYFILE}
PUBKEYFILE=${PRVKEYFILE}.pub
TMPKEY=${KEYFILE}.tmp

ssh-keygen -b 2048 -t rsa -f $PRVKEYFILE

for HOST in $HOSTS; do
  echo $HOST ###
  scp ${PUBKEYFILE} ${HOST}:~/${TMPKEY} && echo OK && \
    ssh ${HOST} "cat ${TMPKEY} >> ~/.ssh/authorized_keys && rm ~/${TMPKEY}" && echo OK
done
```

and I just added (in bold) : 


```
for HOST in $HOSTS; do
  echo $HOST ###
  scp ${PUBKEYFILE} ${HOST}:~/${TMPKEY} && echo OK && \
    ssh ${HOST} [B]"su" && echo OK[/B] && "cat ${TMPKEY} >> ~/.ssh/authorized_keys && rm ~/${TMPKEY}" && echo OK
```


----------



## Ruler2112 (Jan 7, 2010)

I just posted a script I wrote intended to be used by people who run mail servers to detect when somebody tries a brute-force method to guess passwords.  Thought I should link it in here for completeness.


----------



## ta0kira (Jan 8, 2010)

In `bash` I use `alias recall='history | egrep'` so that I can do something like `recall ssh`. Not sure if there's a build-in way to do that.
Kevin barry


----------



## DutchDaemon (Jan 8, 2010)

ta0kira said:
			
		

> In `bash` I use `alias recall='history | egrep'` so that I can do something like `recall ssh`. Not sure if there's a build-in way to do that.
> Kevin barry



Bash has reverse history searching:

`ctl-r ssh`

will give you the last history entry containing 'ssh', and every subsequent `ctl-r` will give you the one before that.


----------



## ta0kira (Jan 8, 2010)

DutchDaemon said:
			
		

> Bash has reverse history searching:
> 
> `ctl-r ssh`
> 
> will give you the last history entry containing 'ssh', and every subsequent `ctl-r` will give you the one before that.


Thanks. I use `!` quite a bit, but I ssh to a lot of different places, calling a lot of different remote commands, so it's nice to see all of them at once.
Kevin Barry


----------



## graudeejs (Jan 11, 2010)

I wrote this script to scan files MUCH faster....
It was inspired by one-liner that I wrote for my GF to scan 47 pages.
She scanned them in about 15 min

You can export files to different format, and set starting counter... Very useful if you scan more than 2 days same book for example

I think many of you will find this script very useful


```
#!/bin/sh

if [ "$1" = "--help" ]; then
	cat << EOF
USAGE: 
  `basename $0` [file_format [start_page]]

WHERE:
  file_format   is any format supported by ImageMagick (default jpg)
  start_page    is used to set counter (default 0)
EOF
	exit 0
fi

Format=${1:-"jpg"}
i=${2:-"0"}

while read -p 'Press Enter to scan. Press q and then Enter to stop  ' a && [ "$a" != "q" ] && [ "$a" != "Q" ]; do
	echo "  Scanning..."
	scanimage | convert - `printf "%0.3d.$Format" $i`
	i=`expr $i + 1`
done

if [ "$Format" = "pdf" ]; then
	echo "TIP: you can use print/pdftk to convert all scanned pdf's to singe file:"
	echo "  pdftk \`ls *.pdf\` output output_file_name.pdf"
fi

exit 0
```

EDIT
latest version available at
http://aldis.git.bsdroot.lv/scan/


----------



## Ruler2112 (Jan 20, 2010)

Just posted another script in the userland coding forum.  This one will spawn a new shell for you in the directory of the port you pass as a parameter.


----------



## LeFroid (Feb 21, 2010)

Heres a few simple scripts I wrote.

Heres a basic script to play any video in your ~/Videos dir

play.py

```
#!/usr/bin/env python

 import sys
 import os

 # what to play the video with
 player = "vlc"
 # arguments, ex 'play "myvid.avi"'
 video = sys.argv[1]
 # home dir
 home = os.path.expanduser('~')

 # combine strings
 execStr = player+" "+home+"/Videos/"+video
 # run execStr
 os.system(execStr)
```

this one is a simple c++ tool to install a port (as root). i'm still not good at c++ so this probably should be written better

you use it like "./port_tool MYPORT" as root

sysinfo.h (i copied this from somewhere)

```
#ifndef SYSINFO_H
#define SYSINFO_H

#define WINDOWS 0
#define BSD 1
#define APPLE 2
#define INTEL 3

#if defined( _WIN64 )
  #define PLATFORM WINDOWS
#elif defined ( __WIN32__ ) || defined( WIN32 ) || defined( _WIN32 )
  #define PLATFORM WINDOWS
#elif defined( __APPLE_CC__ )
  #define PLATFORM APPLE
#elif defined( __INTEL_COMPILER )
  #define PLATFORM INTEL
#else
  #define PLATFORM BSD
#endif

#endif
```

ports.h

```
#ifndef PORTS_H
 #define PORTS_H
 #include <iostream>
 using namespace std;

 class Ports
 {
   public:
       void SearchPort(string pName);
       void InstallPort(string pName);
 };
 #endif
```

ports.cpp

```
#include "ports.h"
#include "sysinfo.h"

 void Ports::SearchPort(string pName)
 {
 #if PLATFORM == BSD
  string install;
  cout << "Locations: " << endl;
  string cmd = "/usr/bin/whereis " +  pName;
  system(cmd.c_str());
  cout << "Would you like to install? (y/n) ";
  cin >> install;
  if ( install == "y"|| install == "Y" || install == "yes" || install == "YES
  {
     InstallPort(pName);
  }else{
     exit(EXIT_SUCCESS);
  }
 #else
   cout << "What are you thinking??" << endl;
 #endif
 }

 void Ports::InstallPort(string pName)
 {
  #if PLATFORM == BSD
     string install = "cd /usr/ports/*/"+pName+" && make install clean";
     system(install.c_str());
  #else
    cout << "Install FreeBSD!" << endl;
  #endif
 }

int main(int argc, char *argv[])
 {
  Ports pt;
  if(argc < 2)
  {
     cout << "Usage: " << argv[0] << " PORTNAME" << endl;
  }else{
     cout << "NOTICE: must be root to install any ports" << endl;
     string prog = argv[1];
     pt.SearchPort(prog);
   }
 }
```


----------



## idle (Mar 9, 2010)

LeFroid said:
			
		

> this one is a simple c++ tool to install a port (as root). i'm still not good at c++ so this probably should be written better



That is a big one. 

What is the difference from code below?


```
#!/bin/sh
make install clean -C /usr/ports/$1
```


----------



## LeFroid (Mar 10, 2010)

idle said:
			
		

> That is a big one.
> 
> What is the difference from code below?
> 
> ...



I prefer c++


----------



## sixtydoses (Mar 11, 2010)

Scripts were inspired by DD's portupdater script. DD is using `# portmaster` and am using `# portupgrade`, hence the modification. Else I'd be more than happy just to use his original script. Probably one day I'll switch to `# portmaster` and DD's original script will come in handy. Thanks much, Dutch.

Requires ports-mgmt/portupgrade, ports-mgmt/portaudit and x11/zenity (optional).

`# updatetree` - Run as cronjob every night at 0300.
If portsnap is already running, portsnapcron will only update its compressed snapshot and the INDEX files. Applies the same if portupgrade or some other 'make' process is running. Else, portsnap will fetch and update the ports tree.


```
#!/bin/sh

hostname=$(hostname)
date=$(/bin/date)

echo "
Portupdater for ${hostname} started at ${date}
"

running=`/bin/ps auxww | /usr/bin/grep -E "portsnap|portupgrade|make" | /usr/bin/grep -v grep`


if [ -n "$running" ]
    then
    echo "
    ========== Fetching and update latest ports snapshot from server. ==================
    "
    portvar="-I cron update"
else
    echo "
    ========== Fetching and update ports tree in ${hostname}. ==================
    "
    portvar="cron update"
fi

/usr/sbin/portsnap ${portvar} || exit 1


echo "
    ========== Portupdater done. ============================================
"
```


`# portupdater` - Run as cronjob once a week at 0400.
Will run portaudit, portsclean, update the ports database and check which ports that need updating. I included a dialog box (x11/zenity) to display the number of ports that need updates and remind me to read /usr/ports/UPDATING because sometimes my fingers are faster than my brain..


```
#!/bin/sh

hostname=$(hostname)
date=$(/bin/date)


echo "
Updating portaudit first.
"
/usr/local/etc/periodic/security/410.portaudit


echo "
======================= Cleaning out all obsolete distfiles. =======================
"

/usr/local/sbin/portsclean -CDDLP || exit 1



echo "
======================= Update ports database file. =======================
"

/usr/local/sbin/portsdb -u || exit 1


echo "
======================= See which ports need updating. =======================
"

OIFS=$IFS
IFS='
'

oldports=$(/usr/local/sbin/portversion -vl '<')

count=0

for i in $oldports
do
        count=`/bin/expr "$count" + 1`
        echo $i
done

IFS=$OIFS


echo "
Number of ports need to be updated: $count.
"


echo "
======================= Warnings from /usr/ports/UPDATING. =======================
"

/usr/bin/grep -B 1 AFFECTS: /usr/ports/UPDATING | /usr/bin/head -20


echo "
See /usr/ports/UPDATING for further details.

============================== Portupdater done. ==============================
"

/usr/local/bin/odmsg ''"$count"' ports need updating. Read /usr/ports/UPDATING before upgrading.' & 2>/dev/null
```


`./odmsg`
I've always had this script in my box for quite sometime so that my remote user can get my attention by prompting me a message.
e.g.: `odmsg 'Tada!'`


```
#!/bin/sh


# Set up the Display
export DISPLAY=:0

# Wake up the screen because it has probably fallen asleep
/usr/local/bin/xset s off
/usr/local/bin/xset -dpms
/usr/local/bin/xset s reset
/usr/local/bin/xscreensaver-command -deactivate > /dev/null


/usr/local/bin/zenity --info --text="$1" 2>/dev/null &


# Allow the screensaver and power saving mode to take effect now that the message has been acknowledged.
/usr/local/bin/xset s on
/usr/local/bin/xset +dpms
```


----------



## Thorny (Mar 11, 2010)

Hello,

i'm using the following script to update all jails after an major-update of the FreeBSD Host-System (for example after updating from version 7 to 8):
http://www.meisterderspiele.de/upgrade-jails-thorny.html

It's quite helpfull if you have a bunch of systems to update.


----------



## graudeejs (Mar 14, 2010)

Here's script to make Really Big screenshots.
This can be used only in FVWM, you need to load FvwmCommandS module
This script will switch to each page and create screenshot, after I created screenshot of each page, it will merge them into one big screenshot, containing virtual desk.

Note don't confuse virtual pages with virtual desks 
virtual pages are in virtual desks 


```
#!/bin/sh

# this script will create screenshot of each virtual page in fvwm
#   then it will merge them into one big jpg
#   then it will switch to Sx Sy page and open screenshot with Start_viewer
#   fvwm function
#
# this script requires fvwm module FvwmCommandS to be loaded
# 
# To integrate in Fvwm, you can do something like this
# 
# Exec exec $[FVWM_SCRIPTS]/RealBigScreenshot.sh $[desk.pagesx] $[desk.pagesy] $[page.nx] $[page.ny]

X=${1:-"1"}	# page count X
Y=${2:-"1"} # page count Y
Sx=${3:-"0"}	# from which pagex we ran this scipt
Sy=${4:-"0"}	# from which pagey we ran this scipt

for y in `jot $Y 0`; do
	for x in `jot $X 0`; do
		FvwmCommand "GotoPage $x $y"
		import -quality 95 -window root /tmp/$$_x${x}_y${y}.jpg
		xnames="$xnames /tmp/$$_x${x}_y${y}.jpg"
	done

	convert +append $xnames /tmp/$$_y${y}.jpg
	rm -f $xnames
	xnames=""
	ynames="$ynames /tmp/$$_y${y}.jpg"
done

if [ ! -d ${HOME}/pic/screenshots ]; then
	mkdir -pf ${HOME}/pic/screenshots
fi

fileName="${HOME}/pic/screenshots/$(date '+%Y.%m.%d_at_%H.%M.%S')-RealBig.jpg"
convert -append $ynames $fileName
rm -f $ynames

FvwmCommand "GotoPage $Sx $Sy"

exec FvwmCommand "Function Start_viewer $fileName"

exit
```

here's example screenshot ([red]Warning this jpg is 1.9MB[/red])





I needed this for my homework in databases 
The database data in screenshot are all fake

EDIT:
latest script version can be found at
http://aldis.git.bsdroot.lv/fvwm-bluth/


----------



## rambetter (Mar 16, 2010)

Hi, I have a couple of scripts that I'm proud of.

The first is similar to ``pkg_delete'', but it also performs a ``make rmconfig'' on the package you are removing.  I call this script ``pkg_clean_delete'':


```
#!/bin/sh

if [ $# -ne 1 ]; then
  echo "Exactly one argument must be specified" 1>&2
  exit 1
fi
PACKAGE=$1
if [ -e "$PACKAGE" ]; then
  echo "'$PACKAGE' is a file; avoid that" 1>&2
  exit 1
fi
ORIGIN=`pkg_info -qo "$PACKAGE"`
if [ $? -ne 0 ]; then
  exit 1
fi
if pkg_delete "$PACKAGE"; then
  cd "/usr/ports/$ORIGIN"
  make clean
  make rmconfig
  exit 0
fi
exit 1
```


I have another script that addresses a real problem I've had.  My servers are in a data center, and for some reason, when I reboot my servers, it sometimes takes 60 seconds or so for the network to start working.  I run ntpd on my servers.  My /etc/ntp.conf file uses DNS names that need to be resolved to IP addresses when ntpd starts.  The problem is that usually, the network is not working by the time ntpd starts, and ntpd cannot perform the DNS resolution.  ntpd then gets into a funny state where two of its processes show up in ps, yet it never finishes resolving DNS, and never works.  I need to shut down ntpd and then restart it after the system comes up in order for it to work.

To fix this issue, I wrote a script that waits for the network to become functional before continuing in the startup scripts.  The file is ``/usr/local/etc/rc.d/waitfornetwork'' and its contents are:


```
#!/bin/sh

# PROVIDE: waitfornetwork
# REQUIRE: NETWORKING
# BEFORE:  named

. /etc/rc.subr

: ${waitfornetwork_enable:=NO}
name=waitfornetwork
rcvar=`set_rcvar`
stop_cmd=":"
start_cmd="waitfornetwork_start"

waitfornetwork_start()
{
  echo "Waiting for network to initialize."
  for i in 0 1 2 3 4 5 6 7 8 9; do
    if ping -c 1 192.203.230.10 | grep -q "^1 packets transmitted, 1 packets received, 0\.0% packet loss$"; then
      return 0
    fi
  done
  warn "Network still seems bo be down."
  return 1
}

load_rc_config ${name}
run_rc_command "$1"
```

The IP address that I'm pinging is one of the root name servers on the West Coast (U.S.A.).  This forces services such as named and ntpd to wait until the network comes up before they start.  If the network never comes up, the script exits after a few ping attempts.


----------



## morbit (Mar 19, 2010)

Extremely simple port updating/cleaning "script".


```
#!/bin/sh

portsnap fetch update && portmaster -a && \
pkg_cleanup && portmaster --check-port-dbdir && \
portmaster --check-depends && echo removed distfiles: && \
rm -vrf /usr/ports/distfiles/* && echo removed workfiles: && \
rm -vrf /usr/ports/*/*/work && portmaster -l | grep installed
```

Suitable to be terminated at pkg_cleanup stage if no fresh ports were built.

I like to be reminded which ports are leaves.

rm /usr/ports/*/*/work is redundant, if portmaster is always used.

PS. "portmaster --packages-build --delete-build-only -a" combination is extremely useful, it uses packages for build dependencies, and deletes them afterward.


----------



## ckester (Mar 19, 2010)

*cd to directory with source for given command*

This began in the thread about favorite aliases, but it's really more about the simple script I wrote to cd to the directory containing the source for a given command.

I setup the following alias

_~/.cshrc_

```
alias src       source $HOME/bin/cdsrc
```

which uses this script

_~/bin/cdsrc_

```
#!/bin/csh

set PORTSDIR = /usr/ports

set d = `whereis -sq $1`

if ( "X$d" == "X" ) then
        set d = `pkg_info -q -W $1`
        if ( "X$d" == "X" ) then
                echo "No source directory found for $1"
        else
                set p = `pkg_info -q -o $d`
                if ( "X$p" == "X" ) then
                        echo "No source directory found for $1"
                else
                        cd ${PORTSDIR}/$p
                endif
        endif
else
        cd $d
endif
```

It works whether the command is from ports or the system.  

It also uses pkg_info's origin switch to find the correct port directory if the command was installed by a package whose name is not the same as the command's.

So *src top* will take you to /_usr/src/usr.bin/top_, and *src sponge* will take you to _/usr/ports/sysutils/moreutils_.


----------



## graudeejs (Mar 26, 2010)

*ipfw scripting*

I use this function in my fpfw scripts to add new rules.
The advantage is that it's easier to find which rule wasn't added if there was problem.
This function should be used to only add rules with numbers


```
#!/bin/sh
cmd="/sbin/ipfw -q"

# add rule to ipfw
# arguments:
# $1 = rule number
# rest args = rule itself
add_rule() {
    no=$1
    shift
    $cmd add $no $* || echo "ERR add_rule:  '$cmd add $no $*'" >&2
}
```

example usage

```
add_rule 00030 fwd 127.0.0.1,spamd tcp from any to me smtp 'in'
```

example output

```
ipfw: getsockopt(IP_FW_ADD): Invalid argument
ERR add_rule:  '/sbin/ipfw -q add 00030 fwd 127.0.0.1,spamd tcp from any to me smtp in'
```


----------



## graudeejs (Mar 27, 2010)

*sh addressbook*

I had to write simple bash {ye, right} addressbook for university.
Well I brought this to brand new level 
This is like 100 times more complex than it was required, but it was fun

This script is only 159 lines of code (including license), 129 lines without license

ladies and gentleman, let me introduce you to my very simple address book written entirely in sh.
Current limitations:
* no spaces in values (even if you quote them). Comment is exception
* can't use | character

~/bin/ashbook:

```
#!/bin/sh

# Copyright (c) 2010, Aldis Berjoza <aldis@bsdroot.lv>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
# 
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above
#    copyright notice, this list of conditions and the following disclaimer
#    in the documentation and/or other materials provided with the
#    distribution.
# 3. Neither the name of the  nor the names of its
#    contributors may be used to endorse or promote products derived from
#    this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

address_book="$HOME/.ashbook"
save_backup=1	# saves backup when removing record if set

awk_output_format='
{
	split($0, f, "|");
	if( f[1] ) print " name:     " f[1];
	if( f[2] ) print " surname:  " f[2];
	if( f[3] ) print " email:    " f[3];
	if( f[4] ) print " phone:    " f[4];
	if( f[5] ) print " address:  " f[5];
	if( f[6] ) print " date:     " f[6];
	if( f[7] ) print " homepage: " f[7];
	if( f[8] ) print " code:     " f[8];
	if( f[9] ) print " comment:  " f[9];
	print "";
}'


if [ ! -f $address_book ]; then
	touch $address_book
	if [ $? -ne 0 ]; then
		echo "ERR: can't create file $address_book" >&2
		exit 1
	fi
fi

help() {
	version=1.0
	prog_name=$(basename $0)
	cat >&2 << EOF
$prog_name v$version is a very simple addressbook written in sh

$prog_name usage:
  $prog_name {add | find | rm} key1=value1 [key2=value2 [...]]
  $prog_name list

    Where key can be any of are:
      name, surname, code, phone, address, position, email, homepage, date,
      comment

    Comment key is special and must be last key used. Comment value may
    contain spaces.
    
    Values and commands are case sensetive, keys are not.

    Use of | character is forbidden as it's used as field seperator in
    addressbook.

EOF
	exit 1
}


if [ "$1" = 'add' ]; then
	func='add'
elif [ "$1" = 'find' ]; then
	func='find'
elif [ "$1" = 'list' ]; then
	awk "$awk_output_format" $address_book
	exit 0
elif [ "$1" = 'rm' ]; then
	func='rm'
else
	help
fi
shift

if [ $# -eq 0 ]; then
	help
	exit 1
fi


while [ $# -gt 0 ]; do
	key=$(echo $1 | sed 's/=.*//' | tr 'QWERTYUIOPASDFGHJKLZXCVBNM' 'qwertyuiopasdfghjklzxcvbnm')
	value=$(echo $1 | sed 's/.*=//')

	case $key in
		'name' | 'surname' | 'code' | 'phone' | 'address' | 'position' | 'email' | 'date' | 'homepage' )
			eval `echo "$key=$value"`;
		;;

		'comment' )
			comment=$(echo $* | sed 's/.*=//')
			break
		;;

		*)
			echo "ERR: key '$key' invalid. Ignoring" >&2
		;;
	esac
	shift
done

find_record="${name:-.*}|${surname:-.*}|${email:-.*}|${phone:-.*}|${address:-.*}|${date:-.*}|${homepage:-.*}|${code:-.*}|${comment:-.*}"

if [ $func = 'add' ]; then
	if [ $(grep -e "$find_record" $address_book) ]; then
		echo 'ERR: looks like this record already exists' >&2
		exit 1
	fi;
	echo "$name|$surname|$email|$phone|$address|$date|$homepage|$code|$comment" >> $address_book
	echo "INFO: Record added"
	exit 0
elif [ $func = 'find' ]; then
	grep -e "$find_record" -x $address_book | awk "$awk_output_format"
	exit 0
elif [ $func = 'rm' ]; then
	found=`grep -e "$find_record" -x $address_book`
	if [ "$found" != "" ]; then
		echo "$found" | awk "$awk_output_format"
		echo "Do you really want to delete above entries? [y|n]"
		read delete
		if [ "$delete" = 'y' ] || [ "$delete" = 'Y' ]; then
			cp -f $address_book ${address_book}.bak
			grep -e "$find_record" -x -v ${address_book}.bak > ${address_book}
			if [ ! $save_backup ]; then
				rm -f ${address_book}.bak
			fi
			echo
			echo "INFO: Record(s) deleted"
		fi
	else
		echo "INFO: No match found"
	fi
	exit 0
fi


exit 1

# vim:tabstop=4:shiftwidth=4:
```

if you think this is any good, please let me know (via pm) and I'll consider improving it and maybe even creating port

Latest version available at:
http://aldis.git.bsdroot.lv/ashbook/


----------



## ckester (Mar 27, 2010)

killasmurf86 said:
			
		

> I had to write simple bash {ye, right} addressbook for university.
> Well I brought this to brand new level
> This is like 100 times more complex than it was required, but it was fun



One of the first lessons I learned when I began my software career many years ago is to never add features that aren't in the spec -- at least, not unless you get the client's agreement and understanding that the project might be delayed or have additional bugs as a result.

Even if it's an in-house job.  My first programming job (late 80's) was at an avionics company.  I spent a lot of time adding bells and whistles to what was expected to be a quick and dirty program.  It was a lot of fun, and I was sure it would impress my boss and anyone else who saw it.  But as a result, I missed out on another assignment that I really really wanted.  When I asked why he hadn't given it to me, my boss said it was because I was still busy on that other thing. He'd thought I'd have the first job done in a day or two, freeing me up in plenty of time to do the plum assignment.  :x


----------



## graudeejs (Mar 27, 2010)

Ye, but simplicity of original task simply offend my level of knowledge


----------



## graudeejs (Mar 27, 2010)

ah, one thing about ashbook script. For now you can't add address with spaces 
I'll see if I can fix this later

you can search partial strings with for example

```
$ ashbook find name=killa.*
```

then again, this won't work

```
$ ashbook find name=.*smurf86
```

EDIT:
http://aldis.git.bsdroot.lv/ashbook/


----------



## gcooper@ (Mar 28, 2010)

LeFroid said:
			
		

> Heres a few simple scripts I wrote.
> 
> Heres a basic script to play any video in your ~/Videos dir
> 
> ...




Use exec family functions so the python script isn't looming in the background after your player has been executed and thus you don't get funky interactions with other applications in terms of signal handling, you don't have unnecessary overhead, etc.
os.path.join is preferred over os.path.sep concatenation.
You aren't properly error checking sys.argv to make sure that at least one argument has been specified.


----------



## gcooper@ (Mar 28, 2010)

chroot_me:

```
#!/bin/sh

SRCBASE=${SRCBASE:-/usr/src}
[ -d "${DESTDIR}" -a -d "${SRCBASE}" ] || exit $?

export UNAME_s=$(uname -s)
export UNAME_m=${UNAME_m:-$(uname -m)}
export UNAME_p=${UNAME_p:-$(uname -p)}
REVISION=$(cd "${SRCBASE}/sys/conf" && grep REVISION= newvers.sh | cut -f2 -d'"')
BRANCH=$(cd "${SRCBASE}/sys/conf" && grep BRANCH= newvers.sh | head -n1 |  cut -f2 -d'"')
export UNAME_r="$REVISION-$BRANCH"
export OSVERSION=$(awk '/\#define.*__FreeBSD_version/ { print $3 }' "$SRCBASE/sys/sys/param.h")
export UNAME_v="$UNAME_s $UNAME_r #0: $(date -v1m -v+1y)	root@$HOSTNAME:$SRCBASE/sys/$UNAME_p/compile/GENERIC"

cp -L /etc/resolv.conf "$DESTDIR/etc/resolv.conf"
[ -c "$DESTDIR/dev/zero" ] || mount -t devfs dev "$DESTDIR/dev"

d=$DESTDIR
s=$SRCDIR

unset DESTDIR SRCBASE 

chroot "$d" /bin/sh

# XXX: exiting immediately and trying to unmount $DESTDIR/dev doesn't always work... hmmm...
sleep 10

umount -f "$DESTDIR/dev"
```

make_usb:

```
#!/bin/sh
#
# A simple script for creating memory disks.
#
# Some of the logic was adapted from release/scripts/make-memstick.sh -- e.g.
# make_usb (thanks kensmith@!)
#

TEN_MB_IN_1K=$((10 * 1024))

# Reporting functions. Nothing much to see here...
die() {
	echo >&2	"${0##*/}: ERROR: $*"
	exit 1
}
info() {
	echo	    "${0##*/}: INFO: $*"
}

# Usage
usage() {
	echo "usage: ${0##*/} [-f mtree-file] input-directory image"
	exit 1
}

# Clean up all consumed memory disks.
cleanup() {
	set +e
	trap : 0 1 2 15
	if [ "x${md_unit}" != x ]; then
		info "cleaning up memory disk"
		mdconfig -d -u ${md_unit}
	fi
	rm -f "${tempfile}"
}

# Create a complete USB image.
#
# 1 - Input directory.
# 2 - Output image (for USB stick).
make_usb() {

	# In order to use mdconfig(1) you should be root -- I realize this is
	# overly conservative, but I'd rather not make this too complicated...
	if [ "x$(id -ru)" != x0 ] ; then
		die "you must be root when executing make_usb"
	fi

	[ $# -eq 2 ] || usage

	[ -d "$1" ] || die "input directory - $1 - doesn't exist"

	set -e

	tempfile=$(mktemp /tmp/usb.XXXXXXXX)

	trap "[ \$? -ne 0 ] && rm -f '$output_image'; cleanup" 0 1 2 15

	in_dir=$1
	output_image=$2

	#sed -e '/^vfs.root.mountfrom.*/d' -i "" "$in_dir/boot/loader.conf"
	#echo 'vfs.root.mountfrom="ufs:/dev/da0a"' >> "$in_dir/boot/loader.conf"

	#makefs -o -O,1,-b,4096,-f,512,-o,space${inode:+,-i,${inode}} -f 1% \

	# Don't want to append to the existing image; this is what happens by
	# default with mdconfig(1), because we used -t vnode.
	rm -f "$output_image"

	makefs_args="${tempfile} ${in_dir}"
	if [ "x$mtreefile" != x ]; then
		makefs_args="-x -F $mtreefile $makefs_args"
	fi
	makefs -f 1% $makefs_args

	#
	# Calculate the needed file size for the mounted image.
	#
	# The calculation is done as shown for the following reason (as verbatim
	# from: .../release/scripts/make_memstick.sh):
	#
	#    Use $BLOCKSIZE for transfers to improve efficiency.  When
	#    calculating how many blocks to transfer "+ 2" is to account for
	#    truncation in the division and to provide space for the label.
	#
	block_count=$(( $(stat -f '%z' "$tempfile") / $TEN_MB_IN_1K + 2))

	# Create the backing file.
	dd if=/dev/zero of=$output_image bs=$TEN_MB_IN_1K count=$block_count

	# Create a new memory disk.
	md_unit=$(mdconfig -a -t vnode -f "$output_image")
	# Partition and label the sucker. Add appropriate bootloader bits to
	# the partition table and slices.
	fdisk -BIq /dev/${md_unit}
	bsdlabel -Bw /dev/${md_unit}
	# Sync the contents on the temporary file to the memory disk.
	dd "if=$tempfile" of=/dev/${md_unit}a bs=$TEN_MB_IN_1K conv=sync

}

# Parse available options and commands.

mtreefile=

while getopts "f:" option; do
	case "$option" in
	f)
		if [ ! -f "$OPTARG" ] ; then
			die "mtree file specified - $OPTARG - doesn't exist or isn't a regular file!"
		fi
		mtreefile=$OPTARG
		;;
	*)
		usage
		;;
	esac
done

shift $(( OPTIND - 1 ))

make_usb $@
```

/etc/rc for an automated install with a predefined payload (was using it for make_usb generated images before my project `changed direction'):

```
#!/bin/sh
#
# A first-time boot rc script which goes in, labels the disks appropriate to
# the config files, newfs's the sucker, then mounts, unwraps the payload, and
# does a basic sanity check to ensure that the system is bootable and
# functional.
#

DESTDIR=${DESTDIR:-/mnt}
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export PKG_PATH=/packages

debug() {
	echo "${0##*/}: DEBUG: $@"
}

info() {
	echo "${0##*/}: INFO: $@"
}

# functions adlibbed from install/stage/etc/rc.

clear_swap() {
	# This always errors out when wiping the entire device; I don't care if
	# it does or not...
	info "Creating swap partition"
	dd if=/dev/zero of=/dev/$1s1b bs=1m 2>/dev/null || :
	swapon /dev/$1s1b
}

cleanup_mountpoints() {
	trap : 0 1 2 15
	set +e
	mounted_destdir=$(mount | awk '$3 != "/" && $3 !~ /^\/dev/ { print $1 }')
	until [ "x${mounted_destdir:-}" = x ]; do
		umount -f ${mounted_destdir}
		mounted_destdir=$(mount | awk '$3 != "/" && $3 !~ /^\/dev/ { print $1 }')
		sleep 1
	done
	[ "x${md_unit}" != x ] && mdconfig -d -u ${md_unit}

}

# Do all `post-install' configuration actions, like generate /etc/fstab, etc.
#
# 1 - Disk
configure_system() {
	generate_fstab $1
	clear_swap $1
}

# Clear all of the data off of a disk.
#
# 1 - Disk
format_disk() {
	fdisk -BIq $1 2>/dev/null >/dev/null
}

# Generate /etc/fstab based on the filesystems mounted under ${DESTDIR}.
#
# 1 - Disk
generate_fstab() {

	old_IFS=$IFS

	IFS="
"

	echo "/dev/$1s1b none swap sw 0 0" > "${DESTDIR}/etc/fstab"

	for i in $(mount); do

		i=$(echo "$i" | sed -e 's# on##g' -e 's#(.*)$##g' -e 's#mnt/*##g')

		case "$i" in
		/dev/$1*)
			echo "$i ufs rw 1 1" >> "${DESTDIR}/etc/fstab"
			;;
		esac

	done

	IFS=$old_IFS

}

# Is the disk real?
#
# 1 - Disk
isa_real_disk() {
	[ -c /dev/$1 ]
}

# Label a disk according to a seemingly logical scheme
label_disk() {

	disklabel -w -r -B /dev/${1}s1 auto

	tmp_label=$(mktemp /tmp/disklabel.XXXXXX)

	cat <<EOF > $tmp_label
a: 4G 16 4.2BSD 2048 16384
b: $(( $(sysctl -n hw.physmem) / 1024 / 1024 ))M *  swap
d: 4G *  4.2BSD 2048 16384
e: 8G *  4.2BSD 2048 16384
f: *  *  4.2BSD 8192 65536
EOF

	disklabel -R /dev/${1}s1 $tmp_label

	rm -f $tmp_label

}

mount_disk() {

	for i in 1a: 1d:usr 1e:var 1f:usr/home; do

		partition="/dev/${1}s$(echo "$i" | cut -d: -f1)"
		mountpoint="${DESTDIR}/$(echo "$i" | cut -d: -f2)"

		debug "Mounting ${partition} on $mountpoint"

		test -d "$mountpoint" || mkdir -p "$mountpoint"
		mount $partition "$mountpoint"

	done

}

newfs_disk() {
	for i in /dev/${1}s1[adef]; do
		newfs -O2 -m 8 -o time $i >/dev/null
	done
}

stage_install() {

	info "Installing base"

	# Copy over the contents of the media to $DESTDIR , skipping over a
	# select set of directories (but not /packages because pkg_add would
	# fold in on itself if it's not present based on the value of
	# getcwd(3), as pkg_add(1) -C chroots into $DESTDIR, and chroot(2)
	# does not actually modify the value of the current directory returned
	# by getcwd(3)).
	#
	# XXX (garrcoop): 1. --exclude for tar(1) should work in this regard,
	# but it doesn't 100% in this case (for some reason). 2. -C for cpf
	# should work as well, but doesn't.
	(cd / ; tar -cpf - $(ls -d * | grep -E -v 'dist|mnt') | tar xpf - -C "$DESTDIR")

	# Override the USB copies of files with their dist/ bretheren.
	(cd /dist ; tar -cpf - . | tar xpf - -C "$DESTDIR")

	sed -e '/^vfs.root.mountfrom/d' -i "" "$DESTDIR/boot/loader.conf"

	if [ -d "$PKG_PATH" ] ; then

		info "Installing packages"

		mount -t devfs dev $DESTDIR/dev

		mountpoints="$DESTDIR/dev $mountpoints"

		# XXX (garrcoop): pkg_add(1) barfs with exit code 1 even when
		# -F and -f are specified; this needs to be fixed.
		(find "$PKG_PATH" -type f | xargs -n 4 pkg_add -C "$DESTDIR" -Ff || :) 2>/dev/null >/dev/null

		rm -Rf "$DESTDIR/$PKG_PATH"

		info "Packages installed"

	fi

	info "Install complete"

}

wipe_disk() {
	info "Wiping disk $1"
	dd if=/dev/zero of=/dev/$1 bs=1m count=1 2>/dev/null || :
}

set -e

md_unit=$(mdconfig -a -t malloc -s $(( 16 * 1024 * 1024 )) )
newfs /dev/$md_unit >/dev/null
mount -t ufs /dev/$md_unit /tmp
trap cleanup_mountpoints 0 1 2 15

# Wait for the devices to be detected.
i=0
while [ $i -lt 15 ] && ! isa_real_disk "$1" ; do
	# Avoid RAIDs, memory disks, and SCSI disks.
	set -- $(sysctl -n kern.disks | awk '{ for (i=1; i <= NF; i++) { if ($i !~ /ar|da|md|mf[0-9]+/) { disks = disks " " $i } } } END { print disks }')
	sleep 2
	: $(( i += 1 ))
done

if [ "x$1" = x ] ; then
	echo "${0##*/}: ERROR: didn't find a configurable harddisk."
	exit 1
else

	for step in wipe format label newfs mount; do
		debug "Calling ${step}_disk on $1"
		eval "${step}_disk $1"
	done

	stage_install
	configure_system $1

	cleanup_mountpoints

	read -p "Remove the CD / USB media and press Enter to continue " j
	init 6

fi
```

Certain hacks are in place for our specific environment, but you're free to use this in whatever way you deem appropriate.

All stuff here BSD licensed of course .


----------



## Ruler2112 (Mar 31, 2010)

ckester said:
			
		

> One of the first lessons I learned when I began my software career many years ago is to never add features that aren't in the spec -- at least, not unless you get the client's agreement and understanding that the project might be delayed or have additional bugs as a result.
> 
> Even if it's an in-house job.



My brother was fired from his job last year because of just this.  He wrote what the person wanted, then expanded it to include cool features.  By the time he was done adding stuff that he thought would be useful, it was so complex that the person it was for couldn't figure out how to use it.  They went around 2-3 times, trying to get it to be what the person wanted, but he really didn't know what he wanted it to do and my brother was guessing based on varied and vague descriptions.  (This didn't come out until much later.)  It was an in-house job and because it didn't do what was wanted, the person had him fired.    My brother has always ripped on me for spending time doing system requirements engineering and getting the document explaining what the system will do initialed on all but the simplest of projects; if he were to have done so, he would not have been fired IMO.

Sorry to go off-topic - this is an important concept for new coders to grasp.  More and better isn't always better.


----------



## gcooper@ (Apr 4, 2010)

Yes. Making life easier is nice, but simplicity is always key; otherwise the added support and complexity is just unruly and a pain.


----------



## gcooper@ (Apr 4, 2010)

Delete empty @pkgdep lines created by unknown source (portmaster?, ports?):


```
find /var/db/pkg/ -name +CONTENTS -mindepth 2 -maxdepth 3 | xargs -J % -n 1 sed -i "" -E -e '/^@pkgdep *$/d' %
```


----------



## graudeejs (Jun 10, 2010)

I just developed playlist randomization for my playd (in pure sh)

this function takes 1 argument (maximal value to return) and return random number 0 to $1

```
playd_rnd() {
# arg1 Max value
  a=$(dd if=/dev/random of=/dev/stdout bs=1 count=4 2>/dev/null | od -D -An)
  b=$(echo "$1 / 4294967296 * $a" | bc -l | sed 's/\..*$//')
  if [ "$b" ]; then
    echo $b
  else
    echo 0
  fi
}
```


----------



## vermaden (Jun 10, 2010)

@killasmurf86

You should accomplish the same with that one-liner:
[CMD=""]% expr ${RANDOM} % 10 + 1[/CMD]

... where 10 is maximum, You may generalize that into:
[CMD=""]% expr ${RANDOM} % ${MAX} + 1[/CMD]


----------



## ProFTP (Jun 10, 2010)

*simple script to correct MySQL database tables*

http://www.x0.org.ua/blog/user/1/view/39

```
#!/usr/bin/perl

use DBI;

my $db_name = 'mysql';

# user from db
my $db_user = 'root';
my $db_pass = '';
my $db_type = 'mysql';
my $db_host = 'localhost';

my $dbh = DBI->connect(
    "DBI:$db_type:database=$db_name;host=$db_host",
    $db_user, $db_pass,
    {
        RaiseError => 1,
        PrintError => 1
    }
) || die $DBI::errstr;

my $sth = $dbh->prepare( 'select Db from db' );
$sth->execute();
my $loop_data;
push @{$loop_data}, $_ while $_ = $sth->fetchrow_hashref();

$sth->finish();
$dbh->disconnect();

foreach my $ii ( @{$loop_data} ) {

    my $db_name = $ii->{Db};

    my $dbh = DBI->connect(
        "DBI:$db_type:database=$db_name;host=$db_host",
        $db_user,
        $db_pass

    );

    my $loop_data2;

    eval {

        my $sth = $dbh->prepare('show tables');
        $sth->execute();

        while ( my @row = $sth->fetchrow_array ) {

            die "bad table name: $row[0]" unless $row[0] =~ /^[w_]+$/;
            push @{$loop_data2}, $row[0];

        }

    };

    next if ($@);

    foreach $_ ( @{$loop_data2} ) {
        $dbh->do( qq{REPAIR TABLE $_ } );
    }

    $dbh->disconnect();

}
```


----------



## ProFTP (Jun 10, 2010)

My Collection scripts (Russian language)
http://unixforum.org.ua/index.php?topic=23928


----------



## Alt (Jun 11, 2010)

Another script for fixing all MYSQL tables in all databases (without shutdown):

```
#!/bin/sh
# Written by Alt 2010. Beer-ware license xD

M_LOGIN="root"
M_PASS="YoUrPaSsWoRd"

DBS=`echo 'show databases;' | /usr/local/bin/mysql -p$M_PASS -u$M_LOGIN | /usr/bin/grep -v Database | /usr/bin/grep -v information_schema | /usr/bin/xargs echo `
for DB in $DBS; do
    echo "DB $DB"
    TBLS=`echo 'show tables;' | /usr/local/bin/mysql -p$M_PASS -u$M_LOGIN $DB | /usr/bin/grep -v Tables | /usr/bin/xargs echo `
    for TBL in $TBLS; do
        echo -n "  Tbl $TBL .. "
        echo "repair table $TBL quick;" | /usr/local/bin/mysql -p$M_PASS -u$M_LOGIN $DB | /usr/bin/grep -v Msg_type
    done
done
/usr/local/bin/mysqladmin -p$M_PASS -u$M_LOGIN flush-tables
```


----------



## ProFTP (Jun 11, 2010)

i think from the beginning we should see whether the table is corrupted ...! (because for a long time ...)
... and then correct ...
but it is not essential ...


----------



## graudeejs (Jun 11, 2010)

vermaden said:
			
		

> @killasmurf86
> 
> You should accomplish the same with that one-liner:
> [CMD=""]% expr ${RANDOM} % 10 + 1[/CMD]
> ...



uhhh, man.... and I had to invent new method just because I couldn't find anything how to get random number

EDIT:
I noticed, that your solution only generates random numbers up till 2^15 [at lest so it seams].
My solution [current implementation] can generate number up 2^32, and I don't see problems making even bigger numbers (just need to modify a bit)


----------



## john_doe (Jun 11, 2010)

vermaden said:
			
		

> You should accomplish the same with that one-liner:
> [CMD=""]% expr ${RANDOM} % 10 + 1[/CMD]


It will not work in sh(1). Use jot(1), e.g.
`$ jot -r 1 0 $(((1 << (8 * [highlight]4[/highlight])) - 1))`
where 4294967295 is max of 4 bytes of /dev/random

And the function can be reduced to
`$ playd_rnd() { jot -r 1 0 $1; }`


----------



## graudeejs (Jun 11, 2010)

john_doe said:
			
		

> It will not work in sh(1). Use jot(1), e.g.
> `$ jot -r 1 0 $(((1 << (8 * [highlight]4[/highlight])) - 1))`
> where 4294967295 is max of 4 bytes of /dev/random
> 
> ...



I can't believe that this was in front of my nose all the time


----------



## graudeejs (Jul 9, 2010)

Here's script that will create zfs snapshots and remove snapshots older than $age seconds
http://aldis.git.bsdroot.lv/zfSnap

This script should be used by cron or something like that

More info:
read this thread http://forums.freebsd.org/showthread.php?t=15737

EDIT:
read wiki http://wiki.bsdroot.lv/zfsnap


----------



## t4z3v4r3d (Jul 10, 2010)

Hello . I'm trying to write a graph er ! script ... and its not good to present .:d
How can i do that ?

```
#!/usr/bin/env bash
clear
# this can be temperature or something else 
# Total line number is 33 !

temp_array=( "" 32 31 31 30 29 28 28 35 37 38 38 39 40 40 41 48 45 44 43 42 40 39 36 )
# THE h line len=32 ! so i should get diffz between start and stop line ! (negatively)
size="${#temp_array[@]}"
	### "Y"
for ((l=1 ; l < $size ; l++ ));do
let "l2=l+$l"
	for ((t=1 ; t <= ${temp_array[$l]} ;t++));do
		let "temp=50-${temp_array[$l]}"
		echo -en "\033[${temp};"$l2"f\033[1;31m *\r \033[0;0m"
  		echo "${temp_array[$l]}"
	done
done
echo	-e "\033[0;0m"
	### "X"
for ((k=1 ; k < 32 ; k++ ));do
 	echo -en "\033[32;$kf\033[32;"$k"d\033[1;31m |\033[0m"
done
echo
```


----------



## Dereckson (Jul 10, 2010)

*Grab your photos from memory card to hard disk*

I wrote this TCL script to copy photos from my memory card to my hard disk.

It copies only new pictures and, if the $GrabPhotos(enableresize) preference is set to 1, will call ImageMagick to create resized version (I found it's quicker to browse 1600x1200 and convenient to have 800x600 versions to send to your contacts).


```
#!/usr/local/bin/tclsh8.5
#
# GrabPhotos.tcl -- Photo memory card helper
# SÃ©bastien Santoro aka Dereckson <dereckson@gmail.com>
#

# # # # # # # # # # # # #
# General configuration #
# # # # # # # # # # # # #

# Where to copy the pics?
set GrabPhotos(targetdir) "~/docs/pics/albums"
# Where are the pics (e.g. your memory card location)?
set GrabPhotos(sourcedir) "/mount/flashmedia"

# On the memory card, where are the pics ?
# set GrabPhotos(picsdir) "" to disable DCIM-like directories lookup
set GrabPhotos(picsdir) DCIM

# If 1, work with any subdirectory from the source
set GrabPhotos(recursive) 1

# Prints an header with credits
set GrabPhotos(printcredits) 0

# verbose prints script action, debug extra details
set GrabPhotos(verbose) 1
set GrabPhotos(debug) 0

# When debug is 1, that also implies verbose to 1, discarding your verbose value
# To disable this behavior, comment the following line (putting a # in front of it) :
if $GrabPhotos(debug) {set GrabPhotos(verbose) 1}

# # # # # # # # # # # # # # # # # # # # #
# Specific configuration :: resize code #
# # # # # # # # # # # # # # # # # # # # #

#This part is if you want to create resised versions with ImageMagick

set GrabPhotos(enableresize) 1
set GrabPhotos(resizeddir) "~/docs/pics/albums/_resized"
set GrabPhotos(sizes) "75x56 800x600 1600x1200"
set GrabPhotos(jpegquality) 80
set GrabPhotos(convert) "/usr/local/bin/convert"
set GrabPhotos(mogrify) "/usr/local/bin/mogrify"

# # # # # # # # # # # # #
# General configuration #
# # # # # # # # # # # # #

# Now, if you just want a copy or a resizing, it's operate as is. Just run it.
# The following code is fully customisable and commented to help you to
# adapt it for your needs.

# # # # # # # # # # # #
# File types handlers #
# # # # # # # # # # # #

# By default, this script handles .jpg files.
# You can add handlers, just creating a proc named handler_ext,
# where ext is the file lowercase extension.
# The file argument is the complete path to the file

# This handlers copy .jpg files to $GrabPhotos(targetdir)/YYYY/YYYY-MM folders
# and then create thumbnails version 

proc handler_jpg {file} {
    global GrabPhotos

    #Gets created time of the file, and then YYYY and MM values
    set ctime [get_created_time $file]
    set YYYY [clock format $ctime -format "%Y"]
    set MM [clock format $ctime -format "%m"]

    #Gets the target directory. Creates it if needed
    set targetdir "$GrabPhotos(targetdir)/$YYYY/$YYYY-$MM"
    if $GrabPhotos(debug) {puts "\nTarget: $targetdir"}
    create_directory $targetdir

    #Copies file if it doesn't exist
    copy_file $file $targetdir

    #Calls resize code if enabled
    if $GrabPhotos(enableresize) {resize $file "$YYYY/$YYYY-$MM"}
}

# # # # # # # # #
# Plugs in code #
# # # # # # # # #

proc resize {file subdir} {
    global GrabPhotos
    if $GrabPhotos(verbose) {puts "Generating resized version from $file"}
    foreach size $GrabPhotos(sizes) {
        set targetdir "$GrabPhotos(resizeddir)/$subdir/$size"
        create_directory $targetdir
        set targetfile "$targetdir/[get_filename $file]"
        if ![file exists $targetfile] {
            #copy_file $file $targetdir
            exec -- $GrabPhotos(convert) [file nativename $file] -resize $size -quality $GrabPhotos(jpegquality) [file nativename $targetfile]
        }
    }
}

# # # # # # # # # # #
# Helper procedures #
# # # # # # # # # # #

proc copy_file {file targetdir} {
    global GrabPhotos
    set fileExists [file exists "$targetdir/[get_filename $file]"]

    if $GrabPhotos(debug) {
        #DEBUG print
        puts -nonewline "Copying $file to $targetdir"
        if $fileExists {
            puts " \[skipped, already exists\]"
        } {
            file copy $file $targetdir
            puts " \[ok\]"
        }
    } elseif !$fileExists {
        file copy $file $targetdir
    }
}

proc create_directory {dir} {
    global GrabPhotos
    if ![file exists $dir] {
        if $GrabPhotos(verbose) {puts "Creating $dir"}
        file mkdir $dir
    }
}


proc get_created_time {file} {
    file stat $file test
    return $test(ctime)
}

proc get_filename {file} {
    lindex [file split $file] end
}

proc parse {directory} {
    global GrabPhotos

    if $GrabPhotos(verbose) {puts "Parsing $directory"}

    #Get files in this directory
    foreach file [glob -nocomplain -directory $directory *] {

        #Another directory, parses it if recursive mode enabled
        if {[file isdirectory $file] && $GrabPhotos(recursive)} {
            parse $file
        } {
            #A regular file, gets the extension and check if we've an handler
            set ext [string tolower [string range [file extension $file] 1 end]]
            set handlerproc [info procs handler_$ext]
            if {$handlerproc != ""} {
                #An handler exists        
                if $GrabPhotos(debug) {puts "Calling $handlerproc $file"}
                $handlerproc $file
            } {
                #File unhandled by a proc
                if $GrabPhotos(verbose) {puts "Ignored file: $file"}
            }
        }
    }

}

proc print_credits {} {
    puts "___________________________________________________________________"
    puts "GrabPhotos 0.1 :: the photo memory card helper"
    puts "___________________________________________________________________"

}

proc print_usage {} {
    puts "Usage: GrabPhotos <source>"
}

# # # # # # # # # #
# Procedural code #
# # # # # # # # # #
if {$argc == 0} {
    if {![info exists GrabPhotos(sourcedir)]} {
        print_credits
        print_usage
        exit
    }
} {
    # Gets sourcedir from argument
    set GrabPhotos(sourcedir) [lindex $argv 0]
}

if {![file isdirectory $GrabPhotos(sourcedir)]} {
    puts stderr "Fatal error: $GrabPhotos(sourcedir) isn't a directory."
    exit
}


if $GrabPhotos(printcredits) {
    print_credits
}

# Go to $GrabPhotos(picsdir) (by default DCIM) directory, if it exists
# If not, we stay in current $GrabPhotos(sourcedir) (by default the script argument)
if [file isdirectory "$GrabPhotos(sourcedir)/$GrabPhotos(picsdir)"] {
    set GrabPhotos(sourcedir) "$GrabPhotos(sourcedir)/$GrabPhotos(picsdir)"
}

parse $GrabPhotos(sourcedir)
```


----------



## Andres (Jul 26, 2010)

The version in shells/tcshrc is missing a few things, like tmux/screen terminfo:

```
set echo_style = 'both'
set title = '$USER@$HOST:ar $cwd'

switch ($TERM)
case {dtterm,rxvt,screen,xterm}*:
	alias cwdcmd 'echo -n "\e]2;'$title'\a"'
	breaksw
case sun*:
	alias cwdcmd 'echo -n "\e]l'$title'\e\\"'
	breaksw
case vt[24]20*:
	alias cwdcmd 'echo -n "\e]0;'$title'\a\e\\"'
	breaksw
default:
	alias cwdcmd 'unalias cwdcmd'
	unset title
endsw

cwdcmd
```


----------



## ProFTP (Aug 2, 2010)

*[Perl] example upload photos to a server with thumbnail previews*

files are not uploaded to the server, php programmers could not solve this problem simply wanted to change hosting 


```
#!/usr/bin/perl

#  @author     Dmitriy Shilenko <q7u5@ukr.net>
# ProFTP 

use warnings;
use strict;
use CGI;
use DBI;
use Image::Magick;

use CGI::Carp qw(fatalsToBrowser);    # used only for tests
# use Data::Dumper;
# $CGI::POST_MAX = 100000000 # maximum file upload size for safety

my $form = new CGI;


# print $form->header; #Print HTML header. this is mandatory



my $p;
%{$p} = $form->Vars;

if (!$p || !%{$p}) {

    print $form->header( -charset => "utf8" );
    #print `pwd`;
    print 'This is perl, my name is Satan666 :)';
    exit;

}



my @a = qw (cid date obj name fam phone age addr project edu more icq status b1 b2 b3 b4 b5 b6 b7 b8 b9 b10 b11 b12 b13 b14 b15 b16 b17 b18 b19 b20 b21 b22 b23 b24);

  @a = map { $p->{$_} || '' } @a;

# print Dumper \@a;
# exit;

my $db_name = '';
# user from db
my $db_user = '';
my $db_pass = '';
#
my $db_type = 'mysql';
my $db_host = 'localhost';

my $prefix = ''; #  prefix table...

my $web_home = "/home/files/";


my $dbh = DBI->connect(
    "DBI:$db_type:database=$db_name;host=$db_host",
    $db_user, $db_pass,
    {
        RaiseError => 1,
        PrintError => 1
    }
) || die $DBI::errstr;


	$dbh->do('INSERT INTO '.$prefix.'_base (cid,date,obj,name,fam,phone,age,addr,project,edu,more,icq,status,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13,b14,b15,b16,b17,b18,b19,b20,b21,b22,b23,b24) 
	
	VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
	', undef, @a );

my $id_db = $dbh->{mysql_insertid};

 my $hash;

my @hash;

# 1..8 foto's
for (0..8) {

 my $key = "foto".($_ == 0 ? "" : $_);
 my $id_file = $_ == 0 ? 1 : ($_+1);
  

 if ( my $UPLOAD_FH = $form->param($key) ) {
 
  uploadfile($UPLOAD_FH,$id_db, $id_file );  
  $hash->{$key} = '/file/'.$id_db.'_'.$id_file.'.jpg';
 
 
 }


}




# print Dumper $hash;


$dbh->do('UPDATE '.$prefix.'_base SET '.( join ", ", map { $_ .' = ? ' } keys %$hash ).' WHERE id='.$id_db.' LIMIT 1', undef, values %$hash ) if ($hash && %$hash);





##this is the only way to send msg back to the client

## print "<script>parent.callback('upload file success')</script>";





sub uploadfile {

 my ($UPLOAD_FH,$id_last, $id_name) = @_;

 my $newfilename = $web_home."or_".$id_last."_".$id_name.".jpg";

 # umask 0000; #This is needed to ensure permission in new file

 open (IMG, ">$newfilename"); binmode IMG;  print IMG while (<$UPLOAD_FH>); close (IMG); chmod 0644, $newfilename; 

 image_thumbnail('100', '100', $newfilename, $web_home."".$id_last."_".$id_name.".jpg");

};




sub image_thumbnail {

 my ($ix, $iy, $file_name, $file_name_out) = @_;

my $photo = Image::Magick->new;
  $photo->Read($file_name); 


my ($ox, $oy, $oc, $ic, $nx, $ny, $geo);
  ($ox,$oy)=$photo->Get('columns','height');
  if (($ox > $ix)||($oy > $iy)) {
   $oc = $ox/$oy; $ic = $ix/$iy;
   if ($oc < $ic) {$ny = $iy; $nx=int(($ox/$oy)*$iy);}
   elsif ($oc > $ic) {$nx = $ix; $ny=int(($oy/$ox)*$ix);}
   else {$nx = $ix; $ny = $iy;}}
  else {$nx=$ox;$ny=$oy;}



  $geo = 'geometry';
  $photo->Resize(geometry=>$geo, width=>$nx, height=>$ny);
  
  $photo->Write($file_name_out);  
    
}

$dbh->disconnect();

	# redirect:

  print $form->redirect( -uri => 'site.com', -status => 301 );


exit;
```

interesting:



```
$dbh->do('UPDATE '.$prefix.'_base SET '.( join ", ", map { $_ .' = ? ' } keys %$hash ).' WHERE id='.$id_db.' LIMIT 1', undef, values %$hash ) if ($hash && %$hash);
```

my blog


----------



## da1 (Sep 8, 2010)

I was searching for a ftp version of sshguard and I couldn't find one. Therefore, I wrote the following. Tested and working with pure-ftpd and pf on 8.0,8.1:
It is not hard to adapt it for ipf or ipfw with other ftp softwares out there.



```
grep="/usr/bin/grep"
awk="/usr/bin/awk"
uniq="/usr/bin/uniq"
ftpguard="/etc/ftpguard.pf"
table="ftpguard"
pfctl="/sbin/pfctl"


if [[ -z $1 ]];then
        echo "Usage: grep_ip_from_file <file_name>"
else
        $grep "\[ERROR\]\ Too\ many\ authentication\ failures" $1 | $awk '{print $6}' | $grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}'| $uniq | while read IP
                do
                   for i in $IP;
                                do
                                   if [[ $i != `$grep $i $ftpguard` ]];
                                then
                                   echo $i >> $ftpguard
                                   $pfctl -t $table -T add $i
                                fi
                                done
                done
fi
```

The script expects that you have a entry in pf.conf like:

```
table <ftpguard> persist file "/etc/ftpguard.pf"
[...]
block in quick on $ext_if proto tcp from <ftpguard> to any port { 21, other ftp related ports } label "ftp bruteforce"
```

and 

```
-rw-------  1 root  wheel  264 Sep  6 12:19 /etc/ftpguard.pf
```

I use crontab to scan /var/log/messages every 10 minutes:

```
*/10    *       *       *       *       root    /path to a folder/ftpguard.sh /var/log/messages &> /dev/null
```
Pls note that I have appended &> /dev/null because I do not want to receive mails about this.


Hope it comes handy for some one.


----------



## graudeejs (Sep 30, 2010)

I wrote perl script to convert /usr/src/sys/kern/syscalls.master to lang/fasm include file

http://aldis.git.bsdroot.lv/asm4FreeBSD/tree/scripts/FreeBSD_syscalls4fasm.pl
here's output:
http://aldis.git.bsdroot.lv/asm4FreeBSD/tree/include/syscalls.fasm


----------



## rbelk (Nov 14, 2010)

After getting asked to many times on how to update the ports system, I wrote the following script. I hope some one finds it useful. If anyone finds an issue, or makes an addition, please forward them back to me. I might submit this to to "portmaster" author and see if he would include it in his port.

I added this script to root's bin directory and chmod'ed it to 0700.


```
#!/bin/sh
#===============================================================================
#
#          FILE:  pmm
# 
#         USAGE:  pmm
# 
#   DESCRIPTION:  A menu driven Shell script for ports management
# 
#       OPTIONS:  None
#  REQUIREMENTS:  /bin/sh, /usr/sbin/pkg_version, /usr/local/bin/portmaster
#          BUGS:  ---
#         NOTES:  ---
#        AUTHOR:  $Author: rbelk $
#       COMPANY:  OnlyBSD
#       VERSION:  $Header: /root/bin/RCS/pmm,v 1.4 2010/11/14 03:35:36 rbelk Exp $
#       CREATED:  $Date: 2010/11/14 03:35:36 $
#      REVISION:  $Revision: 1.4 $
#           LOG:  $Log: pmm,v $
#           LOG:  Revision 1.4  2010/11/14 03:35:36  rbelk
#           LOG:  added the pkg_version requirement
#           LOG:
#           LOG:  Revision 1.3  2010/11/14 03:33:26  rbelk
#           LOG:  cleaned up the comments
#           LOG:
#           LOG:  Revision 1.2  2010/11/14 03:30:19  rbelk
#           LOG:  Update the RCS comments section
#           LOG:
#===============================================================================

while :
do
 clear
 echo "P O R T S - M A I N T I A N C E - M E N U"
 echo ""
 echo "NOTE: You must first do the following steps for PMM to run correctly"
 echo "- Install the ports tree with the command /usr/sbin/portsnap fetch extract"
 echo "- Install portmaster: cd /usr/ports/ports-mgmt/portmaster; make install clean"
 echo "- Add the next line to roots crontab"
 echo "  0 1 * * * /usr/sbin/portsnap cron"
 echo ""
 echo "1. Update the ports tree"
 echo "2. List ports that need to be upgraded"
 echo "3  Update the installed ports"
 echo "4. Cross-check and update dependency information for all ports"
 echo "5. Delete stale distfiles of ports not installed anymore"
 echo "6. Delete stale packages in the package directory"
 echo "7. Delete stale ports that used to be depended on"
 echo "8. Delete stale entries in /var/db/ports"
 echo ""
 echo "Q - Quit"
 echo ""
 echo -n "Please enter option [1 - 8, Q] "
 read opt
 case $opt in
  1) echo "- Updating the ports directory";
         old_time=`ls -lt /usr/ports/UPDATING | awk '{print $6" "$7" "$8}'`
         /usr/sbin/portsnap update
         new_time=`ls -lt /usr/ports/UPDATING | awk '{print $6" "$7" "$8}'`
         if [ "$old_time" != "$new_time" ]
         then
             echo ">>>>>> A T T E N T I O N ---------------------------------------------------"
             echo " /usr/ports/UPDATING has Changed"
             echo "    PLEASE READ BEFORE CONTINUING"
             echo " You might have an installed port that needs attention"
             echo " When you are sure everything is OK, start PMM again and proceded to step 2"
             echo ">>>>>> A T T E N T I O N ---------------------------------------------------"
             exit 1;
         fi
         echo ""
         echo ">>>> Your Next Option is '2' <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  2) echo "- Listing of ports that need to be upgraded";
         /usr/sbin/pkg_version -o -I -L= | awk '{print $1}'
         echo ""
         echo '>>>> Your Next Option is "3" <<<<';
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  3) echo "- Updating the installed ports";
         # /root/bin/update_ports
         /usr/local/sbin/portmaster -a
         echo ""
         echo ">>>> Your Next Option is "4" <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  4) echo "- Cross-checking and updating dependency information for all ports";
         /usr/local/sbin/portmaster --check-depends
         echo ""
         echo ">>>> Your Next Option is "5" <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  5) echo "- Deleting stale distfiles of ports not installed anymore";
         /usr/local/sbin/portmaster --clean-distfiles
         echo ""
         echo ">>>> Your Next Option is "6" <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  6) echo "- Deleting stale packages in the package directory";
         /usr/local/sbin/portmaster --clean-packages
         echo ""
         echo ">>>> Your Next Option is "7" <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  7) echo "- Deleting stale ports that used to be depended on";
         /usr/local/sbin/portmaster -s
         echo ""
         echo ">>>> Your Next Option is "8" <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  8) echo "- Deleting stale entries in /var/db/ports";
         /usr/local/sbin/portmaster --check-port-dbdir
         echo ""
         echo ">>>> Your ports tree should be updated <<<<";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
  Q) echo "Bye $USER";
         exit 1;;
  *) echo "$opt is an invaild option. Please select option between 1-8, or Q only";
         echo "Press [enter] key to continue. . .";
         read enterKey;;
esac
done
```


----------



## vermaden (Nov 14, 2010)

@rbelk

Nice scripts mate, here are my thoughts:



> 1)


diff(1) between old and new UPDATING instead of ATTENTION


> 3)


add addtional options like
  3.1 (do not ask for anything - automatic mode)
  3.2 (use packages if available: -PP option)
  3.3.(other usefull portmaster options)


> GENERAL)


consistency, use name 'ports' or 'packages' everywhere instead of mixing, example:
  echo "6. Delete stale **packages** in the package directory"
  echo "7. Delete stale **ports** that used to be depended on"


----------



## kpedersen (Nov 14, 2010)

Because I like to compile as little software as possible from ports on my already overheating IBM X60 Thinkpad, I devised this little script to run from inside a port folder and tell me a list of package names that I need before this one port will compile.
This does a job which `make missing` fails to do because that lists all the ports to build the dependencies too. I just want the packages. `make run-depends-list' & 'make build-depends-list` don't quite cut it either because they don't take into account ports that are already installed. Also none of them list the package names.

So.. Hopefully I have justified the existence of my script enough... 


```
#ifdef NEVER
g++ $0 -o "$HOME/.port_depends"
"$HOME/.port_depends"
rm "$HOME/.port_depends"
exit
#endif

#include <iostream>
#include <exception>
#include <vector>
#include <string>

using namespace std;

vector<string> packages;
vector<string> ports;

void execute_fetch_list(string command, vector<string>* results)
{
  char output[100];
  FILE* p = NULL;
  string line;

  p = popen(command.c_str(), "r");

  if(p == NULL)
  {
    throw exception();
  }

  while(fgets(output, sizeof(output), p) != NULL)
  {
    line = output;
    results->push_back(line.substr(0, line.length() - 1));
  }

  if(pclose(p) != 0)
  {
    throw exception();
  }
}

string execute_fetch(string command)
{
  char output[100];
  FILE* p = NULL;
  string line;
  vector<string> results;

  p = popen(command.c_str(), "r");

  if(p == NULL)
  {
    throw exception();
  }

  while(fgets(output, sizeof(output), p) != NULL)
  {
    line = output;
    results.push_back(line.substr(0, line.length() - 1));
  }

  if(pclose(p) != 0)
  {
    throw exception();
  }

  return results.at(results.size() - 1);
}

void inspect_port(string port)
{
  vector<string> depends;
  string package;

  for(int portIndex = 0; portIndex < ports.size(); portIndex++)
  {
    if(ports.at(portIndex) == port)
    {
      return;
    }
  }

  ports.push_back(port);
  execute_fetch_list("make -C " + port + " run-depends-list", &depends);

  for(int dependIndex = 0; dependIndex < depends.size(); dependIndex++)
  {
    inspect_port(depends.at(dependIndex));
  }

  package = execute_fetch("make -C " + port + " package-name");

  for(int packageIndex = 0; packageIndex < packages.size(); packageIndex++)
  {
    if(packages.at(packageIndex) == package)
    {
      return;
    }
  }

  cout << package << endl;
}

void safe_main(int argc, char* argv[])
{
  vector<string> runDepends;
  vector<string> buildDepends;

  //populate installedPackages
  execute_fetch_list("pkg_info | awk '{print $1}'", &packages);

  execute_fetch_list("make build-depends-list", &buildDepends);
  execute_fetch_list("make run-depends-list", &runDepends);

  for(int dependIndex = 0; dependIndex < buildDepends.size(); dependIndex++)
  {
    inspect_port(buildDepends.at(dependIndex));
  }

  for(int dependIndex = 0; dependIndex < runDepends.size(); dependIndex++)
  {
    inspect_port(runDepends.at(dependIndex));
  }
}

int main(int argc, char* argv[])
{
  try
  {
    safe_main(argc, argv);
  }
  catch(exception& e)
  {
    cout << "Exception: " << e.what() << "." << endl;
  }

  return 0;
}
```

To get working, copy to your PATH, chmod +x and just make sure that it ends in .cpp or the automatic compiling wont work.. 

Enjoy


----------



## rbelk (Nov 14, 2010)

vermaden said:
			
		

> @rbelk
> 
> Nice scripts mate, here are my thoughts:
> 
> ...



Vermaden, thanks for the feedback. I have a question though. What do you mean by "UPDATING instead of ATTENTION" in your first request. I am checking the /usr/ports/UPDATING to see if it was updated and displaying an attention message.

I also fixed the second request about ports/packages. The 3.1 and 3.2 request can't happen, it's a portmaster thing. I might make a separate script for installing packages. But I am looking into adding other options to pmm.


----------



## kpedersen (Nov 21, 2010)

I call this script "Just stay connected you ****!"


```
#!/bin/sh

ROUTER="192.168.0.1"
IP="192.168.0.4"

while true; do
  echo "Pinging ${ROUTER}..."
  ping -o -t 10 ${ROUTER} > /dev/null 2>&1

  if [ $? != 0 ]; then
    echo "Router did not respond, reconnecting..."
    ifconfig wlan0 inet ${IP} netmask 255.255.255.0
    ifconfig wlan0 down
    route add default ${ROUTER} > /dev/null 2>&1
    wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf -B > /dev/null 2>&1
  else
    echo "Router responded"
  fi

  sleep 30
done
```

This also has the added bonus of my laptop connecting back to the wireless even if the wireless switch has been turned off and on again.

Kinda horrid but it is the only way I currently know which will sort itself out after the iwi (intel 2200bg) has a firmware error etc...


----------



## vermaden (Nov 21, 2010)

rbelk said:
			
		

> Vermaden, thanks for the feedback. I have a question though. What do you mean by "UPDATING instead of ATTENTION" in your first request. I am checking the /usr/ports/UPDATING to see if it was updated and displaying an attention message.


Instead of checking IF it changed, display WHAT have changed, like that:

```
# cd /usr/ports
# cp UPDATING /tmp
# portsnap fetch update
# diff UPDATING /tmp/UPDATING | cut -c 2-1000 | sed -e 1d | sed -e :a -e '$d;N;2,4ba' -e 'P;D'
 20101120:
   AFFECTS: users of x11-toolkits/gtk20 and x11-toolkits/gtkmm24
   AUTHOR: FreeBSD GNOME Team <gnome@FreeBSD.org>
 
   In the GNOME 2.32 release. gdk-pixbuf2 has been split off from gtk20,
   and atkmm has been split off from gtkmm24. To upgrade please use the
   following instructions:
 
   Portmaster users:
 
     # pkg_delete -f gtkmm-2.20\* gtk-2.20\*
     # portmaster -a
 
   Portupgrade users:
 
     # pkgdb -fF
     # pkg_deinstall -fO gtkmm-2.20\* gtk-2.20\*
     # portupgrade -aOW
 
 20101118:
   AFFECTS: users of editors/emacs-devel
   AUTHOR: Ashish SHUKLA <ashish@FreeBSD.org>
 
   Due to a bug when upgrading from 24.0.50.101606, everything
   installed by other ports in "${PREFIX}/share/emacs" gets removed.
 
   Before upgrading:
 
   * Please backup custom configurations in "${PREFIX}/share/emacs".
   * After upgrading reinstall any ports that may have had files in the
     "${PREFIX}/share/emacs" directory.
 
   Apologies for this inconvenience.
```



> I also fixed the second request about ports/packages. The 3.1 and 3.2 request can't happen, it's a portmaster thing.


Its just matter of adding another case with portmaster and its arguments, its needless to create separate scripts for that


----------



## rbelk (Nov 22, 2010)

Thanks Vermaden for the input. I have added your suggestions and put the script up on Google Code. Here's the URL, PMM
Anyone can file a bug report or feature request on the PMM site.
When I modify this script I will post updates to this thread.


----------



## vermaden (Nov 23, 2010)

Welcome.


----------



## graudeejs (Dec 3, 2010)

I've udpated my *ftpwlist* script. This also fixes some bugs 
http://hg.bsdroot.lv/aldis/ftpwlist/


----------



## teckk (Dec 13, 2010)

A small script that I have used to convert a directory of audio files from any of .ra .rm .ram or .wma to .mp3 files with the same name.
It uses mplayer to dump the audio to .wav
It uses lame to encode the .wav to .mp3
It keeps the original audio file
It removed the .wav file.


```
#!/bin/sh
# Change file type references accordingly. This will change .ra .ram .rm .wma to .mp3
# Uses Mplayer to dump to .wav. Encode with lame to mp3

for i in *.ra
do
 if [ -f "$i" ]; then
 rm -f "$i.wav"
 mkfifo "$i.wav"

# Mplayer options here 
 mplayer -vc dummy -vo null -ao pcm:file="$i.wav" "$i" &
 dest=`echo "$i"|sed -e 's/ra$/mp3/'`

# Lame options here 
 lame --resample 16 -b 16 "$i.wav" "$dest"

# Remove the mt .wav file
 rm -f "$i.wav"
fi
done
```


----------



## ProFTP (Dec 21, 2010)

mac.txt

```
/121.conf:NETIF="ifname=eth0,mac=00:18:51:23:9E:B3,host_ifname=veth121.0,host_mac=00:18:51:E1:A5:51,bridge=vmbr0"
./101.conf:NETIF="ifname=eth0,mac=00:18:51:1C:67:42,host_ifname=veth101.0,host_mac=00:18:51:F5:63:28,bridge=vmbr0"
./151.conf:NETIF="ifname=eth0,mac=00:18:51:AE:93:C1,host_ifname=veth555.0,host_mac=00:18:51:5A:EC:85,bridge=vmbr1"
./106.conf:NETIF="ifname=eth0,mac=00:18:51:FE:3B:14,host_ifname=veth106.0,host_mac=00:18:51:D1:76:D2,bridge=vmbr0"
./555.conf:NETIF="ifname=eth0,mac=00:18:51:AE:93:C1,host_ifname=veth555.0,host_mac=00:18:51:5A:EC:85,bridge=vmbr1"
./111.conf:NETIF="ifname=eth0,mac=00:18:51:20:60:D4,host_ifname=veth111.0,host_mac=00:18:51:4E:5A:24,bridge=vmbr1"
./108.conf:NETIF="ifname=eth0,mac=00:18:51:22:A8:2B,host_ifname=veth108.0,host_mac=00:18:51:65:AD:AF,bridge=vmbr1"
./126.conf:NETIF="ifname=eth0,mac=00:18:51:93:2A:0A,host_ifname=veth126.0,host_mac=00:18:51:77:D4:1B,bridge=vmbr0"
./102.conf:NETIF="ifname=eth0,mac=00:18:51:F6:85:E5,host_ifname=veth102.0,host_mac=00:18:51:99:49:34,bridge=vmbr0"
./103.conf:NETIF="ifname=eth0,mac=00:18:51:68:07:A0,host_ifname=veth103.0,host_mac=00:18:51:8F:1E:19,bridge=vmbr0"
./104.conf:NETIF="ifname=eth0,mac=00:18:51:30:42:9C,host_ifname=veth104.0,host_mac=00:18:51:E0:BD:5B,bridge=vmbr0"
./107.conf:NETIF="ifname=eth0,mac=00:18:51:76:76:92,host_ifname=veth107.0,host_mac=00:18:51:BA:2A:EA,bridge=vmbr1"
./110.conf:NETIF="ifname=eth0,mac=00:18:51:F6:85:E5,host_ifname=veth102.0,host_mac=00:18:51:99:49:34,bridge=vmbr0"
```



```
perl -MData::Dumper -0x0a -lne '$hash->{$1}++ while $_ =~ /(((?:(\d{1,2}|[a-fA-F]{1,2}){2})(?::|-*)){6})/smg; END { print Dumper $hash }' maÑ.txt
```


```
$VAR1 = {
          '00:18:51:93:2A:0A' => 1,
          '00:18:51:1C:67:42' => 1,
          '00:18:51:FE:3B:14' => 1,
          '00:18:51:99:49:34' => 2,
          '00:18:51:65:AD:AF' => 1,
          '00:18:51:F5:63:28' => 1,
          '00:18:51:BA:2A:EA' => 1,
          '00:18:51:F6:85:E5' => 2,
          '00:18:51:4E:5A:24' => 1,
          '00:18:51:76:76:92' => 1,
          '00:18:51:E0:BD:5B' => 1,
          '00:18:51:E1:A5:51' => 1,
          '00:18:51:D1:76:D2' => 1,
          '00:18:51:30:42:9C' => 1,
          '00:18:51:AE:93:C1' => 2,
          '00:18:51:77:D4:1B' => 1,
          '00:18:51:8F:1E:19' => 1,
          '00:18:51:23:9E:B3' => 1,
          '00:18:51:5A:EC:85' => 2,
          '00:18:51:22:A8:2B' => 1,
          '00:18:51:20:60:D4' => 1,
          '00:18:51:68:07:A0' => 1
        };
```



MAC regex: http://www.perlmonks.org/?node_id=83405


----------



## graudeejs (Dec 25, 2010)

I wrote this script (adjust as needed) to debug cgi module without using web server
Adjust red lines. Note: It ain't perfec, but it helps A Lot

testcgi.sh

```
#!/bin/sh

URL="[red]http://example.com/edit?id=8394[/red]"
cookie_="[red]SID=b96846d846asdd68a4sd6848asdasd[/red]"
post_="[red]url_title=test&url_description=test&url=test&public=Y&submit=Update[/red]"
export SERVER_PORT="[red]80[/red]"
cgi_name="[red]./Linx.pl[/red]"

#=================================================

get_=`echo $URL | sed -e s'/.*?//'`
post=$(echo "$post_" | sed -f urlencode.sed)

if [ $post_ ]; then
	export REQUEST_METHOD="POST"
else
	export REQUEST_METHOD="GET"
fi
export SERVER_PROTOCOL=`echo $URL | sed -e 's#://.*$##'`
export SERVER_NAME=`echo $URL | sed -E -e 's#^.+//##' -e 's#/.*$##'`
export PATH_INFO=`echo $URL | sed -E -e 's#\?.*##' -e 's#^.*://##' -e "s#^$SERVER_NAME##"`
export CONTENT_LENGTH=`expr "$post" : '.*'`
export QUERY_STRING=$(echo "$get_" | sed -f urlencode.sed)
export HTTP_COOKIE="$cookie_"

echo $post | $cgi_name
```

urlencode.sed

```
s/%/%25/g
#s/\$/%24/g
#s/&/%26/g
#s/+/%26/g
s/,/%2c/g
#s/\//%2f/g
#s/:/%3a/g
#s/;/%3b/g
#s/=/%3d/g
#s/\?/%3f/g
#s/@/%40/g
s/ /%20/g
s/"/%22/g
s/</%3c/g
s/>/%3e/g
s/#/%23/g
s/{/%7b/g
s/}/%7d/g
s/|/%7c/g
s/\\/%5c/g
s/\^/%5e/g
s/~/%7e/g
s/\[/%5b/g
s/\]/%5d/g
s/`/%60/g
s/	/%09/g
```


----------



## graudeejs (Dec 26, 2010)

Oneliner to send some zfs snapshots (that contain "bak" in snapshot name) to remote host and compress them with xz
I compressed snapshots on target pc, because pc that was sending snapshots was much slower.
Link between was direct 1Gbps connection

```
# for i in `zfs list -t snapshot -H | grep bak | awk '{print $1'}`; do zfs send $i | ssh backup.pc xz \> `echo $i | sed 's#/#__#g'`.xz; done
```

This requires sh compatible shell and configured ssh with pub/private key authorization


----------



## darkshadow (Feb 7, 2011)

*shell script to download youtube video*

While using video down loader  plug-in for Firefox , youtube-dl script ,and gnash I had many problem and sometime they refuse to download the video , I wrote this small script with only one dependence wget (no php perl or any thing else), I hope you will enjoy it .

Usage: 

`$ ./script-name vid-url`


----------



## carlton_draught (Mar 21, 2011)

*status_beep*

This script, called "status_beep", will cause the PC speaker in FreeBSD to beep after success or failure of a long script. e.g. 
`# status_beep 2 "portmaster -a"`

I realize that for example, portmaster puts its status (e.g. 1/2) in the terminal title bar, but it's nice to be able to minimize and not be distracted by a lengthy build while working on other stuff (even away from the computer), but be diverted back instantly with a failure beep if something hasn't worked. Or a success beep, so that you can continue with whatever it was you were doing. 

I put the beeping functionality first in my zxfer, but then I thought that there is a need to have this sort of thing in a lot of different applications, not just backups. E.g. updating ports, encoding, etc. In the spirit of Unix, it's nice to have small applications that can use or be used by other applications. And this way I can get the functionality I want without having to pester someone. Enjoy. 


```
!/bin/sh

# This program is used to execute another program and sound a beep on completion,
# with a tune corresponding to the exit status of the program's execution.

beep_type=$1
line_to_execute=$2

#
# Print out usage information
#
usage() {
cat <<EOT
usage: 
     # status_beep beep_type line_to_execute

     Where beep_type is a "1" or a "2". 
        1 beeps on failure, 2 beeps on success or failure.
     And line_to_execute is a unix shell command, e.g "portmaster -a"

     Example:
        # status_beep 2 "portmaster -a"

EOT
}

# main program starts here

# syntax error testing
if [ "$beep_type" != "1" -a "$beep_type" != "2" ]; then
  echo "You must specify a beep type."
  usage
  exit 1
fi


if [ "$line_to_execute" = "" ]; then
  echo "You must specify a line to execute."
  usage
  exit 1
fi

# load the speaker kernel module if not loaded already
speaker_km_loaded=$(kldstat | grep -c speaker.ko)
if [ $speaker_km_loaded = "0" ]; then
  kldload "speaker"
fi

# Execute the line we are trying to execute
$line_to_execute

# Beep appropriately
if [ $? -eq 0 ]; then
  # Success
  if [ "$beep_type" = "2" ]; then
    echo "T255CCMLEG~EG..." > /dev/speaker # success sound  
  fi
else
  # Failure 
  echo "T150A<C.." > /dev/speaker # failure sound
fi

exit 0
```


----------



## vermaden (Mar 23, 2011)

If you are an _Openbox_ user, then this script will generate a _'recent used files'_ submenu, like in _CrunchBang Linux_, but without need for additional GAWK package.

Use that in menu.xml file:
`% grep recent ~/.config/openbox/menu.xml`

```
<menu id="recent" label="recent" execute="openbox_recent.sh" />
```


```
#! /bin/sh

LC_ALL=C
MAX=48
COUNT=0
echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"
tail -r ~/.recently-used.xbel \
  | grep -E "(href|exec)" \
  | while read I
    do
      case $(( ${COUNT} % 2 )) in
        (0) CMD=$(  echo "${I}" | grep -o -E "&apos;.*&apos;" | sed -e s/'&apos;'//g | cut -d % -f 1 | sed 's/[ ]*$//') ;;
        (1) echo "${I}" | grep href 1> /dev/null 2> /dev/null || continue
            FILE=$( echo "${I}" | tr ' ' '\n' | grep href | cut -d \" -f 2 | sed -e s/%22/\'/g -e s/%3C/\</g -e s/%3E/\>/g -e s/%20/\ /g -e s/'file:\/\/'//g )
            echo "  <item label=\"$( echo ${FILE} | sed -e s/_/__/g -e 's,.*/,,' ) ($( echo ${CMD} | sed -e s/_/__/g ))\">"
            echo "    <action name=\"Execute\">"
            echo "      <command>${CMD} '${FILE}'</command>"
            echo "    </action>"
            echo "  </item>"
            ;;
      esac
      COUNT=$(( ${COUNT} + 1 ))
      [ ${COUNT} -lt $(( 2 * ${MAX} )) ] || break
    done
echo "  <separator />"
echo "  <item label=\"clear\">"
echo "    <action name=\"Execute\">"
echo "      <command>rm -f ~/.recently-used.xbel</command>"
echo "    </action>"
echo "  </item>"
echo "</openbox_pipe_menu>"
```

*EDIT:*

I have also added info which application would be used.


----------



## graudeejs (Mar 25, 2011)

Here are my scripts for installing FreeBSD:
http://hg.bsdroot.lv/aldis/install-scripts/summary

Currently only 2 scripts, available:

for installing base FreeBSD with ZFS on my laptop
for adding packages


probably more will come


----------



## carlton_draught (Apr 23, 2011)

*vb2wiki.perl*

Here is my vb2wiki.perl script. It is useful for converting one of these forum posts (e.g. a howto) to Google Code wiki format. I wrote it so that it adequately converts howtos as _I_ write them. Your writing style might use vbulletin forum markup in ways I don't and tags that I don't, and may not give correct output in those cases. In which case, you can either modify the script or write things in the style I do or use the same subset of vbulletin forum markup that I do.


```
#!/usr/local/bin/perl
# Copyright (c) 2011 Ivan Nash Dreckman
# All rights reserved.
# BSD 2 clause license: see http://www.freebsd.org/copyright/freebsd-license.html
# Version: 0.1,  20110423
#
# Program name: vb2wiki
# Converts vbulletin forum post to Google Code wiki format
# usage: # ./vb2wiki vb_post.txt
# output: vb_post.wiki
#
use strict;
use warnings;

# Read the input file argument, and change/add .wiki extension
my $input_file = "";
chomp($input_file=$ARGV[0]);
$_ = $input_file;
if (/\./)
{
  s/\.[^.]+$/.wiki/g;
}
else
{
  $_ = "$_.wiki"
}
my $output_file = $_;		


open(INFO, $input_file);
my @lines = <INFO>;
close(INFO);
my @newlines = ();

foreach $_ (@lines)
{
  chop $_;
  $_ = &translate_size($_,"5","=");
  $_ = &translate_size($_,"4","==");
  $_ = &translate_size($_,"3","===");
  $_ = &translate_cmd($_);
  $_ = &translate_url($_);
  $_ = &translate_file($_);

  # translate bold tag
  s/\[B\]/*/g;
  s/\[\/B\]/*/g;

  # translate italic tag
  s/\[I\]/_/g;
  s/\[\/I\]/_/g;

  # translate CODE tag
  s/\[CODE\]/{{{\n/g;
  s/\[\/CODE\]/\n}}}/g;

  push(@newlines,"$_\n");
}

@lines = ();

my @list_type = "nolist";
my $amount_to_indent=1;

# translate numbered and bulleted lists
foreach $_ (@newlines)
{
  chop $_;
  if (/\[LIST\]/)
  {
    push(@list_type,"bullet");
  }
  elsif (/\[LIST=1\]/)
  {
    push(@list_type,"numbers");
  }
  elsif (/\[\/LIST\]/)
  {
    pop(@list_type);
  }
  else
  {
    my $spaces_to_indent = (@list_type - 1) * 2;
    if (/\[\*\]/)
    {
      s/\[\*\]//g;
      my $space = ' ' x $spaces_to_indent;
      if ("$list_type[$#list_type]" eq "bullet")
      {
        $_ = "$space* $_";
      }
      elsif ("$list_type[$#list_type]" eq "numbers")
      {
        $_ = "$space# $_";
      }
      else
      {
        print "Bad list\n";
	exit 1;
      }

    }
    push(@lines,"$_\n");
  }
}

open(INFO, ">$output_file");
print INFO @lines;
close(INFO);
# end of main part


# functions
sub translate_size
{
  $_ = $_[0];
#  print "this $_\n";
  if (/\[SIZE="$_[1]"\]/)
  {
    s/\[SIZE="$_[1]"\]/$_[2]/g;
    s/\[\/SIZE\]/$_[2]/g;
  }
  $_;
}


sub translate_url
{
  $_ = $_[0];
  if (/\[URL="/)
  {
    s/\[URL="/\[/g;
    s/"\]/ /g;
    s/\[\/URL\]/]/g;
  }
  $_;
}


# This works using the code block method
sub translate_cmd
{
  $_ = $_[0];
  if (/\[CMD="/)
  {
    s/\[CMD="/{{{\n/g;
    s/"\]/ /g;
    s/\[\/CMD\]/\n}}}/g;
  }
  $_;
}


sub translate_file
{
  $_ = $_[0];
  if (/\[FILE\]/)
  {
    s/\[FILE\]/<font color="green">/g;
    s/\[\/FILE\]/<\/font>/g;
  }
  $_;
}
```


----------



## vivek (Apr 25, 2011)

Set apache / nginx DocumentRoot permission to read and root only. 

```
#!/bin/sh
_dir="${1:-.}"
_fperm="0444"
_dperm="0445"
_ugperm="root:root"
chown -R "${_ugperm}" "$_dir"
chmod -R "${_fperm}" "$_dir"
find "$_dir" -type d -print0 | xargs -0 -I {} chmod $_dperm {}
```

Go to vhost like

```
cd /home/httpd/domains/e/example.com && ~/bin/drootreadonly
cd /home/httpd/domains/f/freebsd.org && ~/bin/drootreadonly
~/bin/drootreadonly /path/to/vhost/http
```


----------



## graudeejs (Apr 25, 2011)

Here are scripts I wrote, to search and open manpages in www/surf web frowser

http://hg.bsdroot.lv/aldis/dot.fvwm/file/tip/bin/man_cache.sh
http://hg.bsdroot.lv/aldis/dot.fvwm/file/tip/bin/man_menu.sh

More info here


----------



## graudeejs (May 22, 2011)

Wrote a small perl script *dicewaregen* (http://hg.bsdroot.lv/aldis/dicewaregen/) that generates a Diceware dictionary that you can use to create secure passwords.

More info about Diceware: http://world.std.com/~reinhold/diceware.html.

When I have more time, I will update the script so it can output nice LaTeX documents with an easy-to-print dictionary 

Also submitted port: security/p5-dicewaregen (not available yet).


----------



## graudeejs (May 22, 2011)

killasmurf86 said:
			
		

> Wrote small perl script *dicewaregen* (http://hg.bsdroot.lv/aldis/dicewaregen/) that generated Diceware dictionary that you can use to create secure password
> 
> More info about Diceware: http://world.std.com/~reinhold/diceware.html
> 
> ...



I couldn't resist and added support for LaTeX output


----------



## vermaden (Jun 13, 2011)

*DZEN2 config for FreeBSD system status*

The script below will generate system status line using the *dzen2 *package like that:






Some DZEN2 documentation:
http://dzen.geekmode.org/dwiki/doku.php?id=dzen:command-and-option-list
http://dzen.googlecode.com/svn/trunk/README

dzen.sh

```
#! /bin/sh

date +"^fg(#aaaaaa)date: ^fg(#eeeeee)%Y/%m/%d/%A/%H:%M" | tr '[A-Z]' '[a-z]' | tr -d '\n'

echo -n " ^fg(#dd0000)| ^fg(#aaaaaa)cpu: ^fg(#eeeeee)"

CPU=0
top -b 8 \
  | sed 1,8d \
  | grep -o -E "[0-9]+\.[0-9]+%" \
  | awk -F '.' '{print $1}' \
  | while read I
    do
      CPU=$(( ${CPU} + ${I} ))
      echo ${CPU}
    done | tail -1 | tr -d '\n'

echo -n "%/"

sysctl -n dev.cpu.0.freq | tr -d '\n'

echo -n "MHz/"

sysctl -n dev.cpu.0.temperature | awk -F '.' '{print $1}' | tr -d '\n'

echo -n "C ^fg(#dd0000)| ^fg(#aaaaaa)load: ^fg(#eeeeee)"

sysctl -n vm.loadavg | tr -d -c ' [0-9].' | sed -e 's/\(.*\)./\1/' -e 's/^.\{1\}//g' | tr ' ' '/' | tr -d '\n'

echo -n " ^fg(#dd0000)| ^fg(#aaaaaa)ps: ^fg(#eeeeee)"

sysctl vm.vmtotal | grep -m 1 Processes | grep -o -E ":\ [0-9]+" | tr -d ' :' | tr '\n' '/' | sed 's/\(.*\)./\1/' | tr -d '\n'

echo -n " ^fg(#dd0000)| ^fg(#aaaaaa)mem: ^fg(#eeeeee)"

MEM_PAGE=$( sysctl -n hw.pagesize )
MEM_SIZE=$(( $( sysctl -n vm.stats.vm.v_page_count )     * ${MEM_PAGE} / 1024 / 1024 ))
MEM_INCT=$(( $( sysctl -n vm.stats.vm.v_inactive_count ) * ${MEM_PAGE} / 1024 / 1024 ))
MEM_FREE=$(( $( sysctl -n vm.stats.vm.v_free_count )     * ${MEM_PAGE} / 1024 / 1024 ))
MEM_USED=$(( ${MEM_SIZE} - ${MEM_FREE} ))

echo -n "$(( 100 * ${MEM_USED} / ${MEM_SIZE} ))%/$(( ${MEM_INCT} + ${MEM_FREE} ))M"

echo -n " ^fg(#dd0000)| ^fg(#aaaaaa)ip: ^fg(#eeeeee)$( if_ip.sh )"

echo -n "^fg(#dd0000)| ^fg(#aaaaaa)vol/pcm: ^fg(#eeeeee)$( ( mixer -s vol 2> /dev/null || echo - ) | cut -d ':' -f 2 )/$( ( mixer -s pcm 2> /dev/null || echo - ) | cut -d ':' -f 2 )"

echo -n " ^fg(#dd0000)| ^fg(#aaaaaa)fs: ^fg(#eeeeee)"

zpool list storage | tail -1 | awk '{print $5 "/" $4}' | tr -d '\n'

echo -n " ^fg(#dd0000)| ^fg(#aaaaaa)bat: ^fg(#eeeeee)$( battery.sh 0 0 )"

# KEEP THIS - [ENTER] AT THE END IS NEEDED
echo
```

Other needed scripts are:
if_ip.sh

```
#! /bin/sh

ifconfig | grep -v 127.0.0.1 | grep -q "inet " || {
  echo -n "none "
  exit 1
  }

for I in $( ifconfig -l | sed s/lo0//g )
do
  ifconfig ${I} | grep -q "inet " && {
    echo  -n "${I}/"
    ifconfig ${I} | grep "inet " | awk '{print $2}' | tr '\n' ' '
  }
done
```

battery.sh

```
#! /bin/sh

__exit() {
  echo "ER: such battery not exist"
  exit 1
  }

__time() {
  acpiconf -i ${1} 1> /dev/null 2> /dev/null || __exit
  OUTPUT=$( acpiconf -i ${1} )
  if echo "${OUTPUT}" | egrep -q "present|unknown"
  then
    echo -n "0:0"
  else
    TIME=$( echo "${OUTPUT}" | grep "time" | awk '{print $3}' )
    HOUR=$( echo "${TIME}" | awk -F':' '{print $1}' )
    MINS=$( echo "${TIME}" | awk -F':' '{print $2}' )
    echo -n "${HOUR}:${MINS}"
  fi
  }

__sum() {
  TOTAL=0
  for I in ${@}
  do
    HOUR=$( echo ${I} | awk -F':' '{print $1}' )
    MINS=$( echo ${I} | awk -F':' '{print $2}' )
    TOTAL=$(( ${TOTAL} + ${MINS} + ${HOUR} * 60 ))
  done
  if [ ${TOTAL} -gt 720 ]
  then
    echo -n "[calculating]"
  else
    MINS=$(( ${TOTAL} % 60 ))
    [ ${MINS} -lt 10 ] && MINS="0${MINS}"
    echo -n "$(( ${TOTAL} / 60 )):${MINS}"
  fi
  }

__info() {
  acpiconf -i ${1} 1> /dev/null 2> /dev/null || __exit
  OUTPUT=$( acpiconf -i ${1} )
  if echo "${OUTPUT}" | grep -q "present"
  then
    echo "[gone]"
    exit
  fi
  if ! echo "${OUTPUT}" | grep -q "unknown"
  then
    __sum $( __time ${1} )
    echo -n " "
  fi
  PERCENT=$( echo "${OUTPUT}" | grep -i "remaining capacity" | awk '{print $3}' )
  if [ ${AC} -eq 1 ]; then
    STATE=$( echo "${OUTPUT}" | grep rate | awk '{print $3}' )
    if [ ${STATE} -eq 11 -a "${PERCENT}" = "100%" ]
    then
      echo "(${PERCENT}) [charged]"
    else
      echo "(${PERCENT}) [charging]"
    fi
  else
    echo "(${PERCENT}) [discharging]"
  fi
  }

__infolite() {
  acpiconf -i ${1} 1> /dev/null 2> /dev/null || __exit
  OUTPUT=$( acpiconf -i ${1} )
  if echo "${OUTPUT}" | grep -q "present"
  then
    echo "[gone]"
    exit
  fi
  if ! echo "${OUTPUT}" | grep -q "unknown"
  then
    __sum $( __time ${1} )
  fi
  PERCENT=$( echo "${OUTPUT}" | grep -i "remaining capacity" | awk '{print $3}' )
  if [ ${AC} -eq 1 ]; then
    STATE=$( echo "${OUTPUT}" | grep rate | awk '{print $3}' )
    if [ ${STATE} -eq 11 -a "${PERCENT}" = "100%" ]
    then
      echo "${PERCENT}/+"
    else
      echo "${PERCENT}/+"
    fi
  else
    PERC_INT=$( echo ${PERCENT} | tr -d '%' )
    [ ${PERC_INT} -lt 11 ] && {
      echo "/\${color #dd0000}${PERCENT}\${color}/-"
    } || {
      echo "/${PERCENT}/-"
    }
  fi
  }

AC=$( sysctl -n hw.acpi.acline )

case ${#} in

  (0)
    if [ ${AC} -eq 1 ]
    then
        echo "[A/C]"
        exit 0
    fi
    __sum $( __time 0 ) $( __time 1 )
    echo
    ;;

  (1)
    __info ${1}
    ;;

  (2)
    __infolite ${1}
    ;;

  (*)
    echo "usage: $( basename ${0} ) [BATTERY]";
    exit 1;
    ;;

esac
```


Usage (in ~/.xinitrc file):

```
while sleep 1
do
  dzen.sh
done | dzen2 -fn '-*-fixed-medium-*-*-*-*-100-*-*-*-*-iso8859-2' -bg "#333333"
```


----------



## UNIXgod (Jul 4, 2011)

This is my jail() supervisor. It's a simple script that transverses all the running jails on the system and sends a status report email to the administrator on what ports need updating.

I like to leave little easter eggs in my scripts. It also generates a fortune to give a lonely admin the incentive to read the report =)

My servers name is HAL9000 hence the fun wrapped quotes from the space odyssey. 


```
#!/bin/sh
##########################################################################
# Title      :	jsvisor - BSD jail superviser
# Author     :	Stuart Gerstein <UNIXgod@ruby<no-spam>programmer.net>
# Date       :	2010-09-19
# Requires   :	FreeBSD
# Category   :	File Utilities
##########################################################################
# Description
#    o	"jsvisor" simply runs pkg_version or portversion on currently
#	running jails. It will generate an email to be sent to the admin.
#    o	NOTES: jsvisor will prefer portversion over pkg_version furthermore
#	when portversion is not present in the jail pkg_version is used.
# Examples:
#	This utility is meant for use by the cron(8) facility.
#	enter administrators email under the variable ADMIN below
##########################################################################


ADMIN=YOU@YOUREMAIL.NET 	# THIS NEEDS TO BE SET

J=`jls | tail -n +2 | awk '{print $1}'`
host=`hostname`

pkg_v=/usr/sbin/pkg_version
portv=/usr/local/sbin/portversion

x=1
jailportversion() {
	for I in $J; do
		echo "********************************************************************************" #80 char
		jwhich=`jls | tail -n +2 | awk '{print $3}' | head -${x} | tail +${x}`
		if (jexec $I [ -x $portv ]);
		then
			echo "Executing `basename ${portv}` in jail: ${jwhich}"; 
			echo "${jwhich}'s JID is ${I}"; echo;
			jexec $I ${portv} -vL=; echo;
		else
			echo "Executing `basename ${pkg_v}` in jail ${jwhich}"; 
			echo "${jwhich}'s JID is ${I}"; echo;
			jexec $I ${pkg_v} -v -l '<'; echo;
		fi
		x=`expr ${x} + 1`
	done
}
degenerated=`jailportversion`

# uncomment below when testing
#cat <<EOF 
mail -s "'${host} jail ports version output" ${ADMIN} <<EOF
Generating summery of UNIX jails 
`hostname` at `date`.
****************************
There are currently `jls | tail +2 | wc -l | awk '{print $1}'` running jails:
`jls -d`
****************************
HAL9000: This mission is too important for me to allow you to jeopardize it.

${degenerated}

`/usr/games/fortune -a`

HAL9000: Do you want me to repeat the message, Dr. Floyd?
EOF
```


----------



## vermaden (Jul 5, 2011)

*UPGRADE: dzen2 --> xmobar*

... mostly an update for this post: http://forums.freebsd.org/showpost.php?p=137284&postcount=122






~/scripts/xmobar.sh

```
#! /bin/sh

date +"<fc=#AAAAAA>date:</fc> <fc=#EEEEEE>%Y/%m/%d/%A/%H:%M</fc>" | tr '[A-Z]' '[a-z]'
echo -n " <fc=#dd0000>|</fc> <fc=#aaaaaa>cpu:</fc> <fc=#eeeeee>"
top -b -o res | awk 'NR>8 { gsub(/%/,"",$0); CPU+=$11; } END { split(CPU,cpu,"."); print cpu[1]; }'
echo -n "%/"
sysctl -n dev.cpu.0.freq
echo -n "MHz/"
sysctl -n dev.cpu.0.temperature | awk -F '.' '{print $1}'
echo -n "C</fc> <fc=#dd0000>|</fc> <fc=#aaaaaa>load:</fc> <fc=#eeeeee>"
sysctl -n vm.loadavg | awk '{ print substr($2,0,3) "/" substr($3,0,3) "/" substr($4,0,3) }'
BOOT=$( sysctl -n kern.boottime | awk 'match($0, / sec = [0-9]+/) { $0 = substr($0, RSTART, RLENGTH); print $3 }' )
DATE=$( date +%s )
echo -n " <fc=#dd0000>|</fc> <fc=#aaaaaa>uptime:</fc> <fc=#eeeeee>$( date -r $(( ${DATE} - ${BOOT} - 3600 )) +"%k:%M" | tr -d ' ' )</fc>"
echo -n "</fc> <fc=#dd0000>|</fc> <fc=#aaaaaa>ps:</fc> <fc=#eeeeee>"
sysctl -n vm.vmtotal | awk 'match($0, /Processes/) { gsub(/\)/,"",$11); print $3 "/" $6 "/" $9 "/" $11 }'
echo -n "</fc> <fc=#dd0000>|</fc> <fc=#aaaaaa>mem:</fc> <fc=#eeeeee>"
MEM_PAGE=$( sysctl -n hw.pagesize )
MEM_SIZE=$(( $( sysctl -n vm.stats.vm.v_page_count )     * ${MEM_PAGE} / 1024 / 1024 ))
MEM_INCT=$(( $( sysctl -n vm.stats.vm.v_inactive_count ) * ${MEM_PAGE} / 1024 / 1024 ))
MEM_FREE=$(( $( sysctl -n vm.stats.vm.v_free_count )     * ${MEM_PAGE} / 1024 / 1024 ))
MEM_USED=$(( ${MEM_SIZE} - ${MEM_FREE} - ${MEM_INCT} ))
echo -n "$(( 100 * ${MEM_USED} / ${MEM_SIZE} ))%/$(( ${MEM_USED} ))M"
echo -n "</fc> <fc=#dd0000>|</fc> <fc=#aaaaaa>ip:</fc> <fc=#eeeeee>$( [FILE]if_ip.sh[/FILE] )</fc>"
echo -n "<fc=#dd0000>|</fc> <fc=#aaaaaa>vol/pcm:</fc> <fc=#eeeeee>$( mixer -s vol | awk -F ':' '{printf("%s",$2)}' )/$( mixer -s pcm | awk -F ':' '{printf("%s",$2)}' )</fc> "
echo -n "<fc=#dd0000>|</fc> <fc=#aaaaaa>fs:</fc> <fc=#eeeeee>"
zpool list storage | awk 'END{print $5 "/" $4}'
echo -n "</fc> <fc=#dd0000>|</fc> <fc=#aaaaaa>bat:</fc> <fc=#eeeeee>$( [FILE]battery.sh[/FILE] )</fc>"
```

~/scripts/xmobar_loop.sh

```
#! /bin/sh

while sleep 2
do
  echo -n ' '
  xmobar.sh | tr -d '\n'
  echo
done | xmobar ~/.xmobarrc &
```

~/scripts/if_ip.sh

```
#! /bin/sh

case $( ifconfig | grep -c "inet " ) in
  (1)
    echo -n "none "
    exit 0
    ;;
  (*)
    for I in $( ifconfig -l | sed s/lo0//g )
    do
      ifconfig ${I} | awk -v INTERFACE=${I} 'match($0, /inet /) { printf("%s/%s ",INTERFACE,$2) }'
    done
    ;;
esac
```

~/scripts/battery.sh

```
#! /bin/sh                                    

LIFE=$( sysctl -n hw.acpi.battery.life )
case $( sysctl -n hw.acpi.acline ) in
  (1)
    echo "AC/${LIFE}%"
    ;;
  (0)
    TIME=$( sysctl -n hw.acpi.battery.time )
    HOUR=$(( ${TIME} / 60 ))
    MINS=$(( ${TIME} % 60 ))
    [ ${MINS} -lt 10 ] && MINS="0${MINS}"
    echo "${HOUR}:${MINS}/${LIFE}%"
    ;;
esac
```

*EDIT:* I forgot the ~/.xmobarrc file 

~/.xmobarrc 

```
Config { font         = "xft:inconsolata:size=10:antialias=true"
       , bgColor      = "#222222"
       , fgColor      = "grey"
       , border       = NoBorder
       , borderColor  = "#bb00dd"
       , position     = Static { xpos=1 , ypos=1, width=1438, height=11 }
       , lowerOnStart = True
       , commands     = [ Run StdinReader ]
       , sepChar      = "%"
       , alignSep     = "}{"
       , template     = "%StdinReader% "
       }
```


----------



## graudeejs (Jul 5, 2011)

@ Vermaden,

Why do you do it dzen style? (not that it's better or worse, but it makes things complicated)
xmobar, can read some config file (which is haskell file) and call all your wild scripts from there, with custom delays, avoiding custom loops in sh.

Check this out:
xmobar.hs (in Run lines, last argument is update interval in seconds*10 [That is for 1 second, you write 10])
mixer.sh
layout.sh
colorload.sh

Note that StdinReader, will does what it says it do: read stdin, and write to xmobar.

You can also have some parts aligned to left, center, right 
If you need more info, let me know

For this to work, you pass filename of xmobar.hs as argument for xmobar, when you exec it


----------



## vermaden (Jul 5, 2011)

killasmurf86 said:
			
		

> Why do you do it dzen style?


Because its not more comfortable for me mate, for example:
*Run Com "uname" ["-s","-r"] "" 360000*
... if if would allow me to do it that way:
*Run Com "uname -s -r" 360000*
then it would be fine for me, I would add my 'pipes' here, but with requirement for every argument to be in '"' its PITA for me to put every functionality into separate script while I can have everything in one place.

Yes the argument that putting some less important values into less recent updates will save some CPU power is true, but these 'probes' of mine are very light and consume very little CPU power.

I juts do not want to spread all that 'monitoring' into dozens of little scripts.


----------



## graudeejs (Aug 4, 2011)

*uncue*

Today I practiced ruby and wrote v0.0.1 of *uncue* script

http://hg.bsdroot.lv/aldis/uncue

Right now it's pretty basic script. The purpose of *uncue* is to uncue. In otherword to split media (currently only audio) files with cue sheet.

I will keep developing this scipt further.
My biggest goal (to split audio files) is however almost achieved.

Some highlights:

Tries to check cue file
Tries to find files to uncue
Keeps metadata
Has bugs 
I think for my first Ruby script it's pretty good. Especially that I've only spent one day, to write it 

NOTE: This is so very alpha.... in case you try to uncue your media files, don't throw avay originals for now.

It should be relatively save as long as, cue sheet, has one FILE command and only AUDIO tracks...

Currently it accepts only 1 command line argument, and that argument must be cue filename.
Script depends on multimedia/ffmpeg and lang/ruby19


----------



## graudeejs (Aug 5, 2011)

unclue 0.0.2 should be pretty safe to use
http://hg.bsdroot.lv/aldis/uncue

Found a Major bug (in both 0.0.1 and 0.0.2) .... it will be fixed in 0.0.3


----------



## graudeejs (Aug 7, 2011)

I was improving my desktop scripts and update agentsCtl.sh script
http://hg.bsdroot.lv/aldis/wmscripts/file/tip/agentCtl.sh

The main purpose of this script was to make sure, that gpg-agent and ssh-agend only run one instance.
I rewrote it pretty well (I think)

As side effect, if you add

```
eval `"$WMSCRIPTS_DIR/agentCtl.sh" start all`
```
to your ~/.xinitrc and ~/.shrc I can share agents across X11 and console. Also I can share them accross Logouts 

In few minutes I will adopt this script to be able to work with csh & frieds


----------



## graudeejs (Aug 25, 2011)

Here's script that will exec and then refresh www/uzbl every time some subdirectory is modified.
Useful for web development (Ide from http://railscasts.com/episodes/264-guard), It by no means is a substitute. I was just interested in writing something similar


```
#!/bin/sh

DIR_REFRESH_TIMEOUT=300

LOCK_FILE=".web-dev-uzbl.tmp"
DEFAULT_CONFIG="${XDG_CONFIG_HOME:-$HOME/.config}/uzbl/config"

updated_dirlist() {
	find . -type d | grep -v '/\.' > "$LOCK_FILE"
}

last_updated() {
	cat "$LOCK_FILE" | xargs -n 1 ls -d -D %s -l | awk '{print $6}' | sort | tail -n 1
}


if [ -f "$LOCK_FILE" ]; then
	rm -f "$LOCK_FILE"
	sleep 3
fi

updated_dirlist > "$LOCK_FILE"

{
	[ -f "$DEFAULT_CONFIG" ] && cat "$DEFAULT_CONFIG"
	echo "uri $1"
	
	LAST_UPDATED=0
	i=0
	while [ -f "$LOCK_FILE" ]; do
		sleep 1
		LAST_UPDATED_NOW=`last_updated`
		if [ $LAST_UPDATED -lt $LAST_UPDATED_NOW ]; then
			echo reload_ign_cache
			LAST_UPDATED=$LAST_UPDATED_NOW
		fi

		i=$(($i+1))
		if [ $i -gt $DIR_REFRESH_TIMEOUT ]; then
			updated_dirlist
			i=0
		fi

	done

	exit

} | uzbl-browser -c -

# vim: set ts=4 sw=4 :
```


----------



## expl (Aug 25, 2011)

It would work 1000 times more efficient and responsive/reliable if you wrote this using kevent() api.


----------



## graudeejs (Aug 25, 2011)

expl said:
			
		

> It would work 1000 times more efficient and responsive/reliable if you wrote this using kevent() api.



Inefficient - yes, in-responsive - absolutely not


----------



## expl (Aug 26, 2011)

Instant event handler will be very significantly (thousands of times) more responsive than a time out and compare based mechanism. Maybe not so significant in human noticeable units but it will be literally many times more .


----------



## kpn43 (Sep 8, 2011)

*admin script...*

I made this script only for myself and couple of friend first, but soon it became much bigger project than I planned so why not share it with everyone. It script for doing much of admin/maintenance stuff within one simple command.

You can find it here: http://kpn.kahvipannu.fi/admin

All opinions and ideas etc. are welcome, but since I'm not on this forum on regular basis it would be nice to get feedback with email.


----------



## vermaden (Oct 4, 2011)

*useful MDCONFIG wrapper*

Usage:


```
% [color="Blue"]dd < /dev/zero > FILE bs=1m count=100[/color]
100+0 records in
100+0 records out
104857600 bytes transferred in 2.234466 secs (46927368 bytes/sec)

% [color="blue"]ls -lh FILE[/color]
-rw-r--r--  1 vermaden  vermaden   100M 2011.10.04 15:00 FILE

% [color="blue"]mdconfig.sh -c FILE[/color]
IN: created vnode at /dev/md0

% [color="blue"]mdconfig.sh -l[/color]
md0     vnode     100M  /usr/home/vermaden/FILE

% [color="blue"]mdconfig.sh -d 0[/color]
IN: deleted vnode at /dev/md0
```

Code:

```
#! /bin/sh

__usage() {
  NAME="$( basename ${0} )"
  echo "usage: $( basename ${0} ) OPTION FILE|DEVICE"
  echo
  echo "options:    -l --list   - list existing vnode(s)"
  echo "            -c --create - create new vnode"
  echo "            -d --delete - delete existing vnode"
  echo
  echo "examples: ${NAME} -c ~/FILE"
  echo "          ${NAME} -d 0"
  echo "          ${NAME} -l"
  echo
  exit 1
}

[ ${#} -eq 2 -o ${#} -eq 1 ] || __usage

case ${1} in
  (-l|--list)
    sudo mdconfig -l -v
    ;;

  (-c|--create)
    [ -f ${2} ] || {
      echo "ER: file '${2}' does not exist"
      echo
      __usage
    }
    echo -n "IN: created vnode at /dev/"
    sudo mdconfig -a -t vnode -f ${2}
    ;;

  (-d|--delete)
    [ -c /dev/md${2} ] || {
      echo "ER: device '/dev/md${2}' does not exist"
      echo
      __usage
    }
    sudo mdconfig -d -u ${2}
    echo "IN: deleted vnode at /dev/md${2}"
    ;;

  (*)
    __usage

esac
```


----------



## graudeejs (Oct 16, 2011)

I had enough of updating vim plugins and help tags manually, so I wrote 2 scripts:

This script updates my plugins by downloading tar.gz from github:
update_plugins.sh modified and renamed: https://github.com/graudeejs/dot.vim/blob/master/github_plugin_update.sh

And this script updates all help tags for all doc directories in ~/.vim/
https://github.com/graudeejs/dot.vim/blob/master/update_tags.sh


EDIT, I updated scripts.... so now there's also Makefile:
https://github.com/graudeejs/dot.vim/blob/master/Makefile

enjoy!


----------



## frijsdijk (Oct 29, 2011)

t4z3v4r3d said:
			
		

> Hi
> and a script for cvsup ...



Did you know there is csup(1) for quite a while already? Much quicker..


----------



## SNK (Nov 7, 2011)

```
#!/bin/sh

TMPZIP=$( /usr/bin/mktemp /tmp/hostszip.XXXXXX )
TMPHOSTS=$( /usr/bin/mktemp /tmp/hosts.XXXXXX )

if $( ! /bin/test -e /etc/hosts.original ); then
    echo "  ~  0  ~   Backing up original hosts..."
    /bin/cp /etc/hosts /etc/hosts.original
fi

echo "  ~  1  ~   Fetching..."
/usr/bin/fetch -o $TMPZIP http://hostsfile.mine.nu.nyud.net/hosts.zip

echo "  ~  2  ~   Extracting..."
/usr/bin/tar Oxf $TMPZIP | tr -d '\r' > $TMPHOSTS

echo "  ~  3  ~   Respawning..."
/bin/cat /etc/hosts.original $TMPHOSTS > /etc/hosts
/bin/rm -f $TMPZIP $TMPHOSTS
```

This script will download a (regularly updated) list of more than 95,000 hostnames used for advertising/etc. and append it to your /etc/hosts file. In subsequent runs, /etc/hosts will be respawned from a copy of your original hosts file (saved to /etc/hosts.original) and the fetched list.

There are several versions of this script online, but all for Linux. So I adapted one for FreeBSD: changed shells/bash to sh(1), and removed its dependence on ftp/wget, archivers/unzip, and converters/unix2dos.

Comments are welcome: I am new to shell scripting.

-edit-

Please note that the list is quite comprehensive. It includes, e.g.: 
	
	



```
127.0.0.1       clients2.google.com
127.0.0.1       clients3.google.com
127.0.0.1       clients4.google.com
127.0.0.1       clients5.google.com
```
 These hosts are used to install extensions for Chromium. So uncomment these if necessary.


----------



## idle (Nov 7, 2011)

SNK said:
			
		

> list of more than 95,000 hostnames



Whats wrong with named?


----------



## SNK (Nov 7, 2011)

idle said:
			
		

> Whats wrong with named?



Can you be more specific? The purpose is to block those hosts.


----------



## idle (Nov 7, 2011)

*SNK* 
named(8) - Internet domain name server.
DNS server, that came to substitute hosts file those days, when the quantity of hosts began to grow.


----------



## zeroseven (Nov 8, 2011)

I've been reading up on scripting with the bourne shell... I mashed face agains the wall for a few hours putting together a script to check latency on FreeBSD cvsup servers for fetching/updating ports.


```
#!/bin/sh

#start with cvsup1.freebsd.org
server=1

#intended to error check at the end, haven't implemented yet
fastest=-1 

#some absurd latency to compare to initially
seed=2000.0

echo "Pinging cvsup servers..."
while [ $server -le 18 ]
do
	speed=`ping -nqt 4 cvsup$server.freebsd.org | \
                     grep 'round-trip*' | awk '{n=split($4,array,"/"); print array[2];}'`
	if [ "$speed" != "" ]
		then
		result=`echo "$speed < $seed" | bc -l`
		if [ "$result" -eq 1 ] 
		then
			seed=$speed
			fastest=$server
		fi
	fi
	server=`expr $server + 1`
done;
echo "cvsup$fastest.freebsd.org"
```

Obviously, this only works for US servers at this point...

Edit: Adding to this, I may have a question for clarification.  I came across a few comments on random forums searching for answers, and while looking for the answer to floating point comparison in sh(), I noticed a comment talking about how bc() returns 1 for true and 0 for false and how it was not "bashlike"... This confused me, but agreed with a statement I read elsewhere, how bash and other GNU implementations of software have catered to poor coding and standards, enforcing worse habits.  I guess, I immediately thought of C/C++ that treat 1 or any other non zero value as true and 0 as false.  This would make sense as to why other programs such as bc(), return 1 for true and 0 for false... Right? Why would bash() be any different?


----------



## graudeejs (Nov 8, 2011)

Because 





> There is no Unix in Linux


----------



## wblock@ (Nov 8, 2011)

zeroseven said:
			
		

> I've been reading up on scripting with the bourne shell... I mashed face agains the wall for a few hours putting together a script to check latency on FreeBSD cvsup servers for fetching/updating ports.



Remember that lowest latency is not necessarily the fastest.  Might want to compare with sysutils/fastest_cvsup.


----------



## zeroseven (Nov 8, 2011)

wblock@ said:
			
		

> Remember that lowest latency is not necessarily the fastest.  Might want to compare with sysutils/fastest_cvsup.



Haha.. I knew there was probably a tool for this, I just didn't put in the legwork to try and find it... Really, I was just looking for an excuse to get my hands dirty with a shell script.. I know some C/C++ and and have a little experience with some other languages.  I'm just now starting to read up on things like grep, sed, awk and sh scripting.


----------



## graudeejs (Dec 16, 2011)

Here's userscript to switch youtube to html5=1 automatically


```
// ==UserScript==
// @include http://youtube.com/*
// @include http://*.youtube.com/*
// ==/UserScript==

var l = window.location.href;
var a = l.split('?');
var base_address = a[0];
var params = a[1].split('&');

var html5 = false;
for (var i = 0; i < params.length; i++) {
  if (params[i].match(/^html5=/)) {
    html5 = true;
    break;
  }
}

if (html5 == false) {
  params.push('html5=1');
  var address = [base_address, params.join('&')].join('?');
  window.location.href = address;
}
```


----------



## debguy (Mar 7, 2012)

# I find  union , dis-union  reduce more complicated
# scripting.  The below is "huge list" able, small.


```
#!/bin/sh
set -e
if [ -z "$1" ] || [ -z "$2" ] ; then
cat << EOF >> /dev/stderr
usage: [dis-]union file1 file2
descr: files are sets, lines in are elements (newline separated list)
limit: f1 f2 same as f2 f1, result is sort(1)ed; not in sets order
       very fast w/large file support, not bad for a shell script
       re-ordering result to orig. order is a linear operation
EOF
exit ; fi
[ -f "$1" ]
[ -f "$2" ]
cat "$1" | sort | uniq > s1.$$ ;  cat "$2" | sort | uniq > s2.$$
cat s1.$$ s2.$$ | sort | uniq -d
rm s1.$$ s2.$$
```


```
#!/bin/sh
set -e
if [ -z "$1" ] || [ -z "$2" ] ; then
cat << EOF >> /dev/stderr
usage: [dis-]union file1 file2
descr: files are sets, lines in are elements (newline separated list)
limit: f1 f2 same as f2 f1, result is sort(1)ed; not in sets order
       very fast w/large file support, not bad for a shell script
       re-ordering result to orig. order is a linear operation
EOF
exit ; fi
[ -f "$1" ]
[ -f "$2" ]
cat "$1" | sort | uniq > s1.$$ ;  cat "$2" | sort | uniq > s2.$$
cat s1.$$ s2.$$ | sort | uniq -u
rm s1.$$ s2.$$
```

# X login script(s):

# http://www.sourceforge.net/projects/xdm-options

# dependancy sorting related program and scripts:

# http://www.sourceforge.net/projects/dep-trace


----------



## Dereckson (Mar 8, 2012)

GNOME - Use the FreeBSD logo as main icon

Yesterday, I installed 4 FreeBSD workstations in a public space. The dialog after X launch:
- "Hey, why do we have the GNOME logo instead the distro one?"
- "Well... As I said before, FreeBSD isn't a _distro_ but a full operating system, different than Linux [etc.]"
- "Yes, yes, yes, an OS if you want, but what about the icon?"

I so prepared a small script to fetch the FreeBSD logo, crop and resize it, and replace the places/start-here.png files.


```
#!/bin/sh
#Fetches FreeBSD full logo, crops it and deploys it as Gnome application icon.
#Requires ImageMagick (graphics/ImageMagick port)

GNOME_ICON_PATH=/usr/local/share/icons/gnome

#Fetches logo and crops it
cd /tmp
fetch http://www.freebsd.org/logo/logo-full.png
convert logo-full.png -gravity West -crop 175x175+0+0 logo.png

#Deploys it to gnome icons
convert logo.png -resize 48x48 ${GNOME_ICON_PATH}/48x48/places/start-here.png
convert logo.png -resize 32x32 ${GNOME_ICON_PATH}/32x32/places/start-here.png
convert logo.png -resize 24x24 ${GNOME_ICON_PATH}/24x24/places/start-here.png
convert logo.png -resize 22x22 ${GNOME_ICON_PATH}/22x22/places/start-here.png
convert logo.png -resize 16x16 ${GNOME_ICON_PATH}/16x16/places/start-here.png

#Deletes logo and icons cache
rm logo.png logo-full.png ${GNOME_ICON_PATH}/icon-theme.cache

#User help
echo "FreeBSD logo icon has been installed. To enable it, you need to refresh your GNOME theme."
echo "Menu System > Preferences > Appearance > Button Customize..."
echo "Tab Icons > double-click on your current theme to load new logo icon."
```


----------



## dexxa (Mar 8, 2012)

kpn43 said:
			
		

> I made this script only for myself and couple of friend first, but soon it became much bigger project than I planned so why not share it with everyone. It script for doing much of admin/maintenance stuff within one simple command.
> 
> You can find it here: http://kpn.kahvipannu.fi/admin
> 
> All opinions and ideas etc. are welcome, but since I'm not on this forum on regular basis it would be nice to get feedback with email.



Cool project. But *I* must ask you: why did you write it in bash? Seems a little weird for a program that*'*s made for FreeBSD.


----------



## rob34 (Mar 9, 2012)

*Print $PATH Line by Line*

Sometimes it's difficult to locate a particular directory in a long $PATH variable.  I wrote a quick Perl script to list each $PATH directory line by line.  I named it ppath- Perlpath.

Script:

```
#!/usr/local/bin/perl

use strict;
use warnings;

my $path;
my @paths;

$path = $ENV{'PATH'};
@paths = split(/:/,$path);
foreach (@paths) {
        print $_ . "\n";
}
```

Output:

```
/sbin
/bin
/usr/sbin
/usr/bin
/usr/games
/usr/local/sbin
/usr/local/bin
/home/rob/bin
```


----------



## graudeejs (Mar 9, 2012)

rob34 said:
			
		

> Sometimes it's difficult to locate a particular directory in a long $PATH variable.  I wrote a quick Perl script to list each $PATH directory line by line.  I named it ppath- Perlpath.
> 
> Script:
> 
> ...



`$ echo $PATH | tr ':' ' ' | xargs -n 1 echo`
You can probably write this even shorter


----------



## graudeejs (Mar 9, 2012)

graudeejs said:
			
		

> `$ echo $PATH | tr ':' ' ' | xargs -n 1 echo`
> You can probably write this even shorter



Here's better one
`$ echo $PATH | awk 'BEGIN {RS=":"}; {print $0}'`

this one will respect spaces in directories


----------



## wblock@ (Mar 9, 2012)

How about
`% echo $PATH | tr ':' '\n'`


----------



## graudeejs (Mar 9, 2012)

wblock@ said:
			
		

> How about
> `% echo $PATH | tr ':' '\n'`



Totally forgot, that tr can translate to \n
I tried with sed, but failed, so I just wrote with awk


----------



## aa (Mar 24, 2012)

I frequently use this script when preparing FreeBSD-box since REL-4


```
.type catch
catch is a function
catch ()
{
    [ "$1" ] && $PAGER `which $*`
}
.
.catch mona
#!/bin/sh
ROOT=/tmp/mounts
showbanner(){
cat <<::
---------
my banner
---------

Synopsys:
  mount/unmount any ufs and/or dos filesystems

Changelog:
  version 1.0.4d, last update: 2008.11.5
    (small fix add freebsd release 8 & 9)
  version 1.0.5, last update: 2009.01.03
    (allow more than 1 filter, remaining args
     will be treated as filters. examples added)
  version 1.0.5a, last update: 2010.01.01
    (update: FreeBSD 8+ allows more slices, upto silce-z)

Usage:
  [sh] ${0##*/} mount_arg filesystem_arg filter_args...

Where:
  mount_arg is either mount (read-only, read-write) or unmount
    valid choices are: -m, -mr, -mw and -u
    - preceding dash (-) IS required

  valid choices for filesystem_arg are:
    u, ufs, f, fat, n, nt, ntfs, d, dos, and all
    - could be in any (upper/lower/mixed) case,
    - preceding dash is allowed but not required
    - if not supplied, default to UFS

Examples:
  [sh] ${0##*/} -m -a
  mount all partitions, ufs and dos (fat/ntfs)

  [sh] ${0##*/} -u
  unmount ufs only (dos partition will NOT be unmounted)

  [sh] ${0##*/} -mw ufs ad4s2[a-e] ad8s?[a-e]
  mount read-write ufs disk4 slice 2 and disk8 (any slices)
  partition a to e (usually root, var and usr/local)

Notes:
  when filter_args is given, then the preceding 2 arguments
  (mount and filesystem) must also be supplied

  default mount (-m) is read-only
  root dir will be under $ROOT/BSD or $ROOT/DOS

::
#ROOT=""
#ROOT=/tmp/mounts
}; case "$1" in -[?hH]|--help|[?]) showbanner; exit 0;; esac
printerr() { showbanner; echo -e "Error - $*\nProgram aborted.\n"; exit 1; }

getmountedslices() { local IFS='
'; for dev in `df`; { test "$dev" -a ! "${dev%%/*}" && echo "${dev%% *}" "${dev##* }"; }
}

getmountpoint() {
  test "${1#/}" || { echo "$1"; return 1; }
  test "$MOUNTPOINTS" || MOUNTPOINTS=`getmountedslices`
  local IFS='
'; for pair in $MOUNTPOINTS
  { test -z "${pair##$1 *}" && { echo "${pair##* }"; return 0; } }
}

getMSDOSFS() {
  REL=`sysctl -b kern.osrelease`
  case ${REL%%-*} in
    4.*|7.47*) echo msdos;;
    [5-9].*) echo msdosfs;;
    *) echo msdosfs;;
  esac
}

case "$1" in
  -a) unset mod; set -- "" -a;;
  -m|-mr) mod=ro,;;
  -mw) mod=rw,;;
  -u) unset mod;;
  "") unset mod; showbanner;;
   *) printerr unknown option $1;;
esac

enum_fs() {
  set -f
  local c1="[0-9]" c2="[0-9][0-9]" c3="[1-4][a-z]"
  local sc1="s$c1" sc2="s$c2" sc3="s$c3"
  local FS="" r=""
  test "$UFS" = 1 && r="$r $c1$sc3 $c2$sc3"
  test "$NT4" = 1 -o "$FAT" = 1 && r="$r $c1$sc1 $c1$sc2 $c2$sc1 $c2$sc2"
  for n in $r; { FS="$FS /dev/ad$n /dev/da$n"; }
  set +f; echo $FS
}

getfilters() { test -n "$3" || return; shift 2; echo -n "$@"; }
filters="`getfilters "$@"`"
#filter="$3";
#echo filters="$filters"

UFS=""; NT4=""; DOS=""; FAT="";
case "${2#-}" in
  [aA]|[aA][lL][lL]) UFS=1; NT4=1; FAT=1;;
    #nodes="/dev/ad*s*[0-9ad-z] /dev/da*s*[0-9ad-z]";;
  [dD]|[dD][oO][sS]|[fF]|[fF][aA][tT]|[nN]|[nN][tT]|[nN][tT][fF][sS])
    #nodes="/dev/ad*s*[0-9] /dev/da*s*[0-9]";;
    case "${2#-}" in
      [dD]|[dD][oO][sS]) NT4=1; FAT=1;;
      [fF]|[fF][aA][tT]) FAT=1;;
      [nN]|[nN][tT]|[nN][tT][fF][sS]) NT4=1;;
    esac;;
  ""|[uU]|[uU][fF][sS]) UFS=1;;
    #nodes="/dev/ad*s[1-4][ad-z] /dev/da*s[1-4][ad-z]";;
  *) echo unknown filesystem identifier: $2; exit 1;;
esac
nodes="`enum_fs`"

#Constants:
BSD=BSD
DOS=DOS

AA=999:999
OWNER="-uaa -gaa"
OWNER=""

opt_UFS="noatime -t ufs"
opt_DOS="noatime,noexec,nosuid,nodev"
opt_DOS="noatime,noexec,nosuid"         #FreeBSD7 no longer accepts nodev
opt_NT4="-m775 -t ntfs" #could never be written anyway
                        #limited (if any at all) write only for small system
opt_NT4="-m775"
opt_FAT="-m664,-M775 -t `getMSDOSFS`"

MOUNTPOINTS=`getmountedslices`

for node in $nodes; do test -e "$node" || continue
  #[ "$filter" ] && [ "${node##*$filter*}" ] && continue

  SKIP=""
  if [ "$filters" ]; then SKIP=1
    for f in $filters; do
      test -z "${node##*$f*}" && { SKIP=""; break; }
    done
  fi

  [ "$SKIP" ] && continue

  test "$1" != -u && mountpt="`getmountpoint $node`" && {
    echo -n $node already mounted in: $mountpt\ ;
    test -w $mountpt && echo "(rw)" || echo "(ro)"
    test -z ""; continue;
  }

  slice=s"${node#/dev/*s}"      # = s2a
  chunk="${node%$slice}"        # = /dev/ad2
  dev="${chunk#/dev/}"          # = ad2

  disk=""       #disk="$root/$dev"
  mountpoint="" #mountpoint="$disk/$dev$slice"

  __setmountvars() { # got vars: disk, mountpoint
    test "$1" -a ! "$2" || printerr "invalid construct: [$@]"
    #echo disk=$disk slice=$slice mountpoint=$mountpoint
    case "$1" in
      UFS) test -z "${slice%%*[1-4][ad-z]}" || return 1
        root=$ROOT/$BSD; OPTS="$mod$opt_UFS";;
      DOS|FAT|NT4) test -z "${slice%%*[0-9]}" || return 1
        root=$ROOT/$DOS; OPTS="$mod$opt_DOS"
        test $1 = FAT && OPTS="$OPTS,$opt_FAT" || OPTS="$OPTS $opt_NT4"
        OPTS="$OPTS $OWNER";;
      *) printerr unknown filesystem: $*;;
    esac
    disk=$root/$dev             # /mnt/UFS/ad2
    mountpoint=$disk/$dev$slice # /mnt/UFS/ad2/ad2s2a
    #echo now disk=$disk slice=$slice mountpoint=$mountpoint
  }

  __delif_empty() { test -d "$1" -a "$1/*" = "`echo $1/*`" && rm -R "$1"; }
  __delife_all() { __delif_empty $mountpoint; __delif_empty $disk; }
  __mountcheck() { __setmountvars $1 && echo "  $1: $node will be mounted on $mountpoint"; }

  # updated for freebsd7's minor bug: does not return error on failed mount_ntfs
  __mount() { __setmountvars $1 || return
    [ "$1" = "NT4" ] && FBSD7_BUG=_ntfs || unset FBSD7_BUG
    test -d $mountpoint || { mkdir -p $mountpoint && \
      chown $AA $mountpoint || printerr $mountpoint creation failed; }
      (mount$FBSD7_BUG -o $OPTS $node $mountpoint > /dev/null 2>&1) && \
      echo "mounted $1 in $mountpoint (${mod%,})" && return
    __delife_all; return 1 #must be returns fail
  }
  __unmount() { __setmountvars $1 || return
    test -d $mountpoint && umount $mountpoint && \
      echo "  unmounted $1: $node on $mountpoint"
    __delife_all
  }

  case "$1" in
    -m|-m[wr])
      test "$UFS" = 1 && __mount UFS && continue
      test "$NT4" = 1 && __mount NT4 && continue
      test "$FAT" = 1 && __mount FAT && continue
      #echo "*** failed to mount $node";;
      ;;
    -u)
      test "$UFS" = 1 && __unmount UFS
      test "$FAT" = 1 -o "$NT4" = 1 && __unmount DOS
      #echo "*** failed to unmount $node";;
      ;;
    "")
      test "$UFS" = 1 && __mountcheck UFS && continue
      test "$FAT" = 1 -o "$NT4" = 1 && __mountcheck DOS  && continue
      #echo "*** invalid $node";;
      ;;
  esac

done

#test "$1" || { echo; showbanner; }

.
```


----------



## debguy (Apr 12, 2012)

```
# these can make some script list processing problems
# easier to make and understand - and are efficient as sort.
#


#!/bin/sh
set -e
if [ c"$1" = c"-h" ] ; then
cat << EOF >> /dev/stderr
USAGE: [intersection union complement complement-intersection] [-n] file1 file2
DESCR: files are flat sets, lines in are elements (newline list)
       these small shell scripts simplify list work [in scripts]
       show all not in both (c-i) : Comp [ Union[s1,s2] , Int[s1,s2] ]
limit:
       uses sort(1), use -n for numberic for numberic sets, uses uniq(1)
EOF
exit ; fi
[ c"$1" = c"-n" ] && p="-n" && shift
[ -f "$1" ] && [ -f "$2" ] || exit 0
cat "$1" "$2" | sort $p | uniq -d
```


```
#!/bin/sh
set -e
if [ c"$1" = c"-h" ] ; then
cat << EOF >> /dev/stderr
USAGE: [intersection union complement complement-intersection] [-n] file1 file2
DESCR: files are flat sets, lines in are elements (newline list)
       these small shell scripts simplify list work [in scripts]
       show all not in both (c-i) : Comp [ Union[s1,s2] , Int[s1,s2] ]
limit:
       uses sort(1), use -n for numberic for numberic sets, uses uniq(1)
EOF
exit ; fi
[ c"$1" = c"-n" ] && p="-n" && shift
[ ! -f "$1" ] && exit 0
cat "$1" "$2" | sort $p | uniq
```


```
#!/bin/sh
set -e
if [ c"$1" = c"-h" ] ; then
cat << EOF >> /dev/stderr
USAGE: [intersection union complement complement-intersection] [-n] file1 file2
DESCR: files are flat sets, lines in are elements (newline list)
       these small shell scripts simplify list work [in scripts]
       show all not in both (c-i) : Comp [ Union[s1,s2] , Int[s1,s2] ]
limit:
       uses sort(1), use -n for numberic for numberic sets, uses uniq(1)
EOF
exit ; fi
[ c"$1" = c"-n" ] && p="-n" && shift
[ ! -f "$1" ] && exit 0
cat "$1" | sort $p | uniq > s1.$$
[ ! -f "$2" ] && cat s1.$$ && rm s1.$$ && exit
intersection $p "$1" "$2" > s2.$$
cat s1.$$ s2.$$ | sort $p | uniq -u
rm s1.$$ s2.$$
```



```
#!/bin/sh
set -e
if [ c"$1" = c"-h" ] ; then
cat << EOF >> /dev/stderr
USAGE: [intersection union complement complement-intersection] [-n] file1 file2
DESCR: files are flat sets, lines in are elements (newline list)
       these small shell scripts simplify list work [in scripts]
       show all not in both (c-i) : Comp [ Union[s1,s2] , Int[s1,s2] ]
limit:
       uses sort(1), use -n for numberic for numberic sets, uses uniq(1)
EOF
exit ; fi
[ c"$1" = c"-n" ] && p="-n" && shift
[ ! -f "$1" ] && exit 0
cat "$1" "$2" | sort $p | uniq -u
```

intersection  union  complement  complement-intersection

OOPS ^^^ names for the above


----------



## debguy (Apr 12, 2012)

# This little sed(1) line below reads in an "/etc/config" that is an easy to edit and free floating Left Right file for a user to work with, for a script that needs to read in LR settings (assuming the script is not allowed to just source'ing the config to assign variables, assuming script may need one L to many R; list support).


```
scr=':lbl;/^[[:space:]+]/{H;n;x;s/[[:cntrl:]+]/ /g;x;b lbl};x;/^./p'

IFS=$'\n'
for ea_line in `cat $file | sed -e 's/#.*$//' | sed -ne $scr` ; do

IFS=$' \t'
for ea_str in $ea_line ; do
   foo
   # first str is left label, all other are rights
done

# That reads in an "easy edit" slipshod file like the below :)  ...

# COMMAND       DEPENDANCY to meet before command
# (label of)    (filename that must exist, but see Detours)

goal            end
terminal        %bogus        # some comment
request         begin  terminal
end             begin terminal request records-begin remove-list
                install-list command-list response pre-check
                post-check records-end show-result clean
goal            end

# # (see [url]www.souceforge.net/projects/dep-trace[/url] for shmake(1)
```

Rights can be split across lines anywhere until a left is visited - making it a "readable" and "editable" file.


----------



## graudeejs (Apr 12, 2012)

debguy said:
			
		

> OOPS - website striped the carriage returns and tabs.
> Rights can be split across lines anywhere until a left is visited - making it a "readable" and "editable" file.



Ups... you didn't use the 
	
	



```
tags
```


----------



## DutchDaemon (Apr 13, 2012)

Yeah, can you stop dumping unformatted posts on the forum, debguy? I am not going to clean up forever:
http://forums.freebsd.org/showthread.php?t=11799


----------



## graudeejs (May 20, 2012)

graudeejs said:
			
		

> I had enough of updating vim plugins and help tags manually, so I wrote 2 scripts:
> 
> This script updates my plugins by downloading tar.gz from github:
> update_plugins.sh modified and renamed: https://github.com/graudeejs/dot.vim/blob/master/github_plugin_update.sh
> ...



Updated and renamed script to update_plugin
Now it also supports gitorious.


----------



## abefar (May 27, 2012)

*System updating script*

I wrote a small script for my own use for making the daily update checking process (using portmaster) on my boxes easier. It can also check jails for updates using ezjail.
The script has two modes of operation: ports (portsnap -> portmaster) and source (csup).

I am pretty much a bash newbie, but I hope that someone will find it useful anyway. 


```
#!/usr/local/bin/bash
#

################
### SETTINGS ###
################

# FreeBSD branch to check out - change to match
# installed version (or newer if upgrading)
SUPBRANCH="RELENG_9_0"

# Which CVSup mirror to use
SUPHOST="cvsup.dk.freebsd.org"

# Use compression when checking out sources?
SUPCOMP=1

# Check jails for updates, too?
CHECK_JAILS=1

# If yes, list of jails to check
JAILS=('jail1' 'jail2' 'jail3')

# Editor when PAGER variable is not set
DEFAULTPAGER="less"

# Name of the script (auto-detected)
SCRIPTNAME=$(basename $0)

# Path for system updating supfile (recreated every time)
SUPFILE=/tmp/$SCRIPTNAME-supfile

# Miscellaneous paths
# (leave at defaults)
EZJAIL_BIN="/usr/local/bin/ezjail-admin"
PORTSNAP_BIN="/usr/sbin/portsnap"
PORTMASTER_BIN="/usr/local/sbin/portmaster"
PORTAUDIT_BIN="/usr/local/sbin/portaudit"
JAILS_DIR="/usr/jails"
PORTS_DIR="/usr/ports"

############
### CODE ###
############

if [ `id -u` -ne 0 ]; then
	echo "Please run this script as root. Exiting."
	exit 1
fi

if [ ! -x $PORTSNAP_BIN ]; then
	echo "Portsnap not installed. Exiting."
	exit 1
fi

if [ ! -x $PORTMASTER_BIN ]; then
	echo "Portmaster not installed. Exiting."
	exit 1
fi

if [ ! -x $EZJAIL_BIN ]; then
	echo "Ezjail not installed. Skipping jails."
	echo
	CHECK_JAILS=0
fi

case $1 in
	ports)
		if [ -x $PORTAUDIT_BIN ]; then
			read -p "Check for vulnerabilities? [N/y] " yn
			if [ "$yn" = "Y" -o "$yn" = "y" ]; then
				echo -n "Fetching latest vulnerabilities..."
				$PORTAUDIT_BIN -Fq
				echo "done"
				echo
				echo -n "Checking host system: "
				/usr/sbin/pkg_info | awk '{ print $1 }' | xargs $PORTAUDIT_BIN
				if [ $CHECK_JAILS == 1 -a ${JAILS[0]} ]; then
					for jail in ${JAILS[@]}; do
						echo -n "Checking '$jail' jail: "
						$EZJAIL_BIN console -e '/usr/sbin/pkg_info' $jail | awk '{ print $1 }' | xargs $PORTAUDIT_BIN
					done
				fi
			fi
		else
			echo
			echo "Portaudit not installed. Skipping vulnerability checks."
		fi
		echo

		read -p "Update ports tree? [Y/n] " yn
		if [ "$yn" != "N" -a "$yn" != "n" ]; then
			$PORTSNAP_BIN fetch update
		fi
		echo

		read -p "Check host system for updates? [Y/n] " yn
		if [ "$yn" != "N" -a "$yn" != "n" ]; then
			$PORTMASTER_BIN -L
		fi

		if [ $CHECK_JAILS == 1 -a ${JAILS[0]} ]; then
		for jail in ${JAILS[@]}; do
			echo
			if [ -x $JAILS_DIR/$jail$PORTMASTER_BIN ]; then
				read -p "Check '$jail' for updates? [Y/n] " yn
				if [ "$yn" != "N" -a "$yn" != "n" ]; then
					$EZJAIL_BIN console -e '$PORTMASTER_BIN -L' $jail
				fi
			else
				echo "Portmaster not installed on jail '$jail'. Skipping."
			fi
		done
		echo
		fi

		read -p "Read /usr/ports/UPDATING? [Y/n] " yn
		if [ "$yn" != "N" -a "$yn" != "n" ]; then
			${PAGER:=$DEFAULTPAGER} /usr/ports/UPDATING
		fi
		echo
	;;

	sys)
		read -p "Update system sources? [Y/n] " yn
		if [ "$yn" != "N" -a "$yn" != "n" ]; then
			echo -n "Creating a supfile for $SUPBRANCH at $SUPFILE..."
			echo "*default host=$SUPHOST" > $SUPFILE
			echo "*default base=/var/db" >> $SUPFILE
			echo "*default prefix=/usr" >> $SUPFILE
			echo "*default release=cvs tag=$SUPBRANCH" >> $SUPFILE
			echo "*default delete use-rel-suffix" >> $SUPFILE
			if [ $SUPCOMP -eq 1 ]; then
				echo "*default compress" >> $SUPFILE
			fi
			echo "src-all" >> $SUPFILE
			echo "done"
			/usr/bin/csup -L 1 $SUPFILE
		fi
		echo

		read -p "Read /usr/src/UPDATING? [Y/n] " yn
		if [ "$yn" != "N" -a "$yn" != "n" ]; then
			${PAGER:=$DEFAULTPAGER} /usr/src/UPDATING
		fi
		echo
	;;

	*)
		echo "USAGE: $SCRIPTNAME [ports | sys]"
	;;
esac
```


----------



## UNIXgod (May 27, 2012)

abefar said:
			
		

> I wrote a small script for my own use for making the daily update checking process (using Portmaster) on my boxes easier. It can also check jails for updates using ezjail.
> The script has two modes of operation: ports (portsnap -> portmaster) and src (csup).
> 
> I am pretty much a Bash newbie, but I hope that someone will find it useful anyway.
> ...



Your script looks good. In fact it looks like posix so you could use #!/bin/sh. As a pet peeve of mine I prefer any external applications to use env() for portability (i.e. #!/usr/bin/env bash) This would be the same for ruby, perl etc. Though your script is FreeBSD specific I guess it really doesn't matter.

If you'd like to transverse the jails running you can use jls() and create a list from there to run your commands with jexec(). Here is an example to get the current running jails for use with jexec:


```
jls | tail -n +2 | awk '{print $1}'
```

If you need the names you can change the awk print statement to $3 and ip addresses are $2.

Here is an old script I used for jails to generate a report on out of date packages with pkg_version() and/or portversion if installed. Maybe you might find it useful for your jails supervision scripts as it has no actual dependencies on ports.

https://forums.freebsd.org/showpost.php?p=139538&postcount=123


----------



## graudeejs (Jun 19, 2012)

I'm using x11/slim as my login manager.

Today I had this idea:


> Why not to save last used WM and use that as default next time I log in



Slim doesn't support this. But it doesn't have to. Everything you need is to adjust you ~/.xinitrc

The magic code snippet

```
DEFAULT_WM="fvwm"
if [ "$1" ]; then
    export WM="$1"
else
    export WM="$DEFAULT_WM"
    [ -f "$HOME/.last_wm" ] && WM="`cat "$HOME/.last_wm"`"
fi

echo "$WM" > "$HOME/.last_wm"

# now exec your WM
```

Here's my full ~/.xinitrc
https://github.com/graudeejs/dot.files/blob/master/dot.xinitrc


----------



## vermaden (Jul 26, 2012)

*change national characters to ASCII equivalents*

If You move files from one filesystem to another, especially to FAT32/NTFS and then back to UNIX filesystems, then You probably had encoding issues because of 'national' characters, which means unable to locate the file while You know its there or unable to remove it.

The solution to this is to rename/keep all files in ASCII names, so wherever they go, they are 'safe'.

Its 'configurable' by changing the ASCII='...' line, the default is:
`ASCII="echo \"${FILE}\" ${TR} ${Tr} ${Or} ${OdQ}"`

Which also translates various variants of '-' to ASCII one, â„¢ to TM, Â® to R and removes ! character.

It also can be 'configured' to remove brackets, both (/) and [/] and {/}.

Below is the script that I use to make such ASCII 'normalizations', and an example.


```
% [B][color="Blue"]ls [/color][/B]
Ã…Ã†?Ä„Ã‡Ä†ÄŒÄŽÃÃ‰ÃˆÃŠÃ‹Ä˜ÄšÆÆÅ’Ä’ÃÃŽÃÃŒÄ¸Ä¹Ä½ÅÃ‘Å‡ÅƒÅŠÃ”Ã–ÅÃ’Ã˜Ã“Ã•Å”Å˜?Î’ÃŸÅœÅžÅ ÅšÅ¤Ã™ÃšÃ›ÃœÅ®Å°Å¸ÃÅ½Å»Å¹,â€”â€“â„¢Â®![](){}
Ã Ã¡Ã¢Ã¤ÄƒÃ£Ã¥Ã¦ÉÄ…Ã§Ä‡ÄÄÃ°Ã©Ã¨ÃªÃ«Ä™Ä›É›É™Å“Ä“Ã­Ã®Ã¯Ã¬Ä¸ÄºÄ¾Å‚Ã±ÅˆÅ„Å‹Ã´Ã¶Å‘Ã²Ã¸Ã³ÃµÅ•Å™ÃŸÎ²Å¿ÅÅŸÅ¡Å›Å¥Ã¹ÃºÃ»Ã¼Å¯Å±Ã¿Ã½Å¾Å¼ÅºÃ€ÃÃ‚Ã„Ä‚Ãƒ
% [B][color="blue"]toascii.sh *[/color][/B][color="Gray"] (without brackets removal)[/color]
% [B][color="blue"]ls[/color][/B]
AAAACCCDDEEEEEEEEEEIIIIKLLLNNNNOOOOOOORRSSSSSSSTUUUUUUYYZZZ.--TMR[](){}
aaaaaaaaaacccddeeeeeeeeeeiiiiKlllnnnnooooooorrSsssssstuuuuuuyyzzzAAAAAA
% [B][color="blue"]toascii.sh *[/color][/B] [color="gray"](with brackets removal)[/color]
% [B][color="blue"]ls[/color][/B]      
AAAACCCDDEEEEEEEEEEIIIIKLLLNNNNOOOOOOORRSSSSSSSTUUUUUUYYZZZ.--TMR
aaaaaaaaaacccddeeeeeeeeeeiiiiKlllnnnnooooooorrSsssssstuuuuuuyyzzzAAAAAA
```

toascii.sh

```
#! /bin/sh

[ ${#} -eq 0 ] && {
  echo "usage: ${0##*/} FILE|DIRECTORY"
  exit 0
}

a0=" | tr 'Ã ' 'a' "; A0=" | tr 'Ã€' 'A' ";
a1=" | tr 'Ã¡' 'a' "; A1=" | tr 'Ã' 'A' ";
a2=" | tr 'Ã¢' 'a' "; A2=" | tr 'Ã‚' 'A' ";
a3=" | tr 'Ã¤' 'a' "; A3=" | tr 'Ã„' 'A' ";
a4=" | tr 'Äƒ' 'a' "; A4=" | tr 'Ä‚' 'A' ";
a5=" | tr 'Ã£' 'a' "; A5=" | tr 'Ãƒ' 'A' ";
a6=" | tr 'Ã¥' 'a' "; A6=" | tr 'Ã…' 'A' ";
a7=" | tr 'Ã¦' 'a' "; A7=" | tr 'Ã†' 'A' ";
a8=" | tr 'É' 'a' "; A8=" | tr 'â±¯' 'A' ";
a9=" | tr 'Ä…' 'a' "; A9=" | tr 'Ä„' 'A' ";
c0=" | tr 'Ã§' 'c' "; C0=" | tr 'Ã‡' 'C' ";
c1=" | tr 'Ä‡' 'c' "; C1=" | tr 'Ä†' 'C' ";
c2=" | tr 'Ä' 'c' "; C2=" | tr 'ÄŒ' 'C' ";
d0=" | tr 'Ä' 'd' "; D0=" | tr 'ÄŽ' 'D' ";
d1=" | tr 'Ã°' 'd' "; D1=" | tr 'Ã' 'D' ";
e0=" | tr 'Ã©' 'e' "; E0=" | tr 'Ã‰' 'E' ";
e1=" | tr 'Ã¨' 'e' "; E1=" | tr 'Ãˆ' 'E' ";
e2=" | tr 'Ãª' 'e' "; E2=" | tr 'ÃŠ' 'E' ";
e3=" | tr 'Ã«' 'e' "; E3=" | tr 'Ã‹' 'E' ";
e4=" | tr 'Ä™' 'e' "; E4=" | tr 'Ä˜' 'E' ";
e5=" | tr 'Ä›' 'e' "; E5=" | tr 'Äš' 'E' ";
e6=" | tr 'É›' 'e' "; E6=" | tr 'Æ' 'E' ";
e7=" | tr 'É™' 'e' "; E7=" | tr 'Æ' 'E' ";
e8=" | tr 'Å“' 'e' "; E8=" | tr 'Å’' 'E' ";
e9=" | tr 'Ä“' 'e' "; E9=" | tr 'Ä’' 'E' ";
i0=" | tr 'Ã­' 'i' "; I0=" | tr 'Ã' 'I' ";
i1=" | tr 'Ã®' 'i' "; I1=" | tr 'ÃŽ' 'I' ";
i2=" | tr 'Ã¯' 'i' "; I2=" | tr 'Ã' 'I' ";
i3=" | tr 'Ã¬' 'i' "; I3=" | tr 'ÃŒ' 'I' ";
k0=" | tr 'Ä¸' 'k' "; K0=" | tr 'Ä¸' 'K' ";
l0=" | tr 'Äº' 'l' "; L0=" | tr 'Ä¹' 'L' ";
l1=" | tr 'Ä¾' 'l' "; L1=" | tr 'Ä½' 'L' ";
l2=" | tr 'Å‚' 'l' "; L2=" | tr 'Å' 'L' ";
n0=" | tr 'Ã±' 'n' "; N0=" | tr 'Ã‘' 'N' ";
n1=" | tr 'Åˆ' 'n' "; N1=" | tr 'Å‡' 'N' ";
n2=" | tr 'Å„' 'n' "; N2=" | tr 'Åƒ' 'N' ";
n3=" | tr 'Å‹' 'n' "; N3=" | tr 'ÅŠ' 'N' ";
o0=" | tr 'Ã´' 'o' "; O0=" | tr 'Ã”' 'O' ";
o1=" | tr 'Ã¶' 'o' "; O1=" | tr 'Ã–' 'O' ";
o2=" | tr 'Å‘' 'o' "; O2=" | tr 'Å' 'O' ";
o3=" | tr 'Ã²' 'o' "; O3=" | tr 'Ã’' 'O' ";
o4=" | tr 'Ã¸' 'o' "; O4=" | tr 'Ã˜' 'O' ";
o5=" | tr 'Ã³' 'o' "; O5=" | tr 'Ã“' 'O' ";
o6=" | tr 'Ãµ' 'o' "; O6=" | tr 'Ã•' 'O' ";
r0=" | tr 'Å•' 'r' "; R0=" | tr 'Å”' 'R' ";
r1=" | tr 'Å™' 'r' "; R1=" | tr 'Å˜' 'R' ";
s0=" | tr 'ÃŸ' 's' "; S0=" | tr 'áºž' 'S' ";
s1=" | tr 'Î²' 's' "; S1=" | tr 'Î’' 'S' ";
s2=" | tr 'Å¿' 's' "; S2=" | tr 'ÃŸ' 'S' ";
s3=" | tr 'Å' 's' "; S3=" | tr 'Åœ' 'S' ";
s4=" | tr 'ÅŸ' 's' "; S4=" | tr 'Åž' 'S' ";
s5=" | tr 'Å¡' 's' "; S5=" | tr 'Å ' 'S' ";
s6=" | tr 'Å›' 's' "; S6=" | tr 'Åš' 'S' ";
t0=" | tr 'Å¥' 't' "; T0=" | tr 'Å¤' 'T' ";
u0=" | tr 'Ã¹' 'u' "; U0=" | tr 'Ã™' 'U' ";
u1=" | tr 'Ãº' 'u' "; U1=" | tr 'Ãš' 'U' ";
u2=" | tr 'Ã»' 'u' "; U2=" | tr 'Ã›' 'U' ";
u3=" | tr 'Ã¼' 'u' "; U3=" | tr 'Ãœ' 'U' ";
u4=" | tr 'Å¯' 'u' "; U4=" | tr 'Å®' 'U' ";
u5=" | tr 'Å±' 'u' "; U5=" | tr 'Å°' 'U' ";
y0=" | tr 'Ã¿' 'y' "; Y0=" | tr 'Å¸' 'Y' ";
y1=" | tr 'Ã½' 'y' "; Y1=" | tr 'Ã' 'Y' ";
z0=" | tr 'Å¾' 'z' "; Z0=" | tr 'Å½' 'Z' ";
z1=" | tr 'Å¼' 'z' "; Z1=" | tr 'Å»' 'Z' ";
z2=" | tr 'Åº' 'z' "; Z2=" | tr 'Å¹' 'Z' ";

Oco=" | sed s/,/./g";
Oh0=" | tr 'â€”' '-' ";
Oh1=" | tr 'â€“' '-' ";
Otm=" | sed s/'â„¢'/'TM'/g ";
Ore=" | tr 'Â®' 'R' ";
OdQ=" | tr -d '!' ";
Ob0=" | tr -d '[' "; OB0=" | tr -d ']' ";
Ob1=" | tr -d '(' "; OB1=" | tr -d ')' ";
Ob2=" | tr -d '{' "; OB2=" | tr -d '}' ";

Tr="${Tr} ${a0} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9} ${c0}"
Tr="${Tr} ${c1} ${c2} ${d0} ${d1} ${e0} ${e1} ${e2} ${e3} ${e4} ${e5} ${e6}"
Tr="${Tr} ${e7} ${e8} ${e9} ${i0} ${i1} ${i2} ${i3} ${k0} ${l0} ${l1} ${l2}"
Tr="${Tr} ${n0} ${n1} ${n2} ${n3} ${o0} ${o1} ${o2} ${o3} ${o4} ${o5} ${o6}"
Tr="${Tr} ${r0} ${r1} ${s0} ${s1} ${s2} ${s3} ${s4} ${s5} ${s6} ${t0} ${u0}"
Tr="${Tr} ${u1} ${u2} ${u3} ${u4} ${u5} ${y0} ${y1} ${z0} ${z1} ${z2}"

TR="${TR} ${A0} ${A1} ${A2} ${A3} ${A4} ${A5} ${A6} ${A7} ${A8} ${A9} ${C0}"
TR="${TR} ${C1} ${C2} ${D0} ${D1} ${E0} ${E1} ${E2} ${E3} ${E4} ${E5} ${E6}"
TR="${TR} ${E7} ${E8} ${E9} ${I0} ${I1} ${I2} ${I3} ${K0} ${L0} ${L1} ${L2}"
TR="${TR} ${N0} ${N1} ${N2} ${N3} ${O0} ${O1} ${O2} ${O3} ${O4} ${O5} ${O6}"
TR="${TR} ${R0} ${R1} ${S0} ${S1} ${S2} ${S3} ${S4} ${S5} ${S6} ${T0} ${U0}"
TR="${TR} ${U1} ${U2} ${U3} ${U4} ${U5} ${Y0} ${Y1} ${Z0} ${Z1} ${Z2}"

Os="${Oh0} ${Oh1} ${Otm} ${Ore} ${Oco}"

Od="${Ob0} ${OB0} ${Ob1} ${OB1} ${Ob2} ${OB2} ${OdQ}"

for FILE in "${@}"
do
  ASCII="echo \"${FILE}\" ${TR} ${Tr} ${Os} ${Od}"
  mv "${FILE}" "$( eval ${ASCII} 2> /dev/null )"
done
```

Any suggestions welcome


----------



## Dereckson (Jul 27, 2012)

Good morning,

I don't like your solution, as it creates more problems than it solves.

Here some thoughts about the way you handle this issue:

 The solution doesn't solve the problem you announce it solved (FAT32/NTFS -> UNIX filesystem file moves).
 This method shows disdain to your international users: their glyphs are't allowed on your system.
 The script doesn't care about proper transliteration. For example, ÃŸ should be replaced by ss (like s0=" | tr 'ÃŸ' 'ss' ").
 There is a vocabulary issue, letting know you've some progress to do (or you don't really care) about l10n. For example, a language doesn't match a country, so â€œnational charactersâ€ doesn't mean anything. You even need non ASCII characters in English too. Here two filenames I've found Wikimedia Commons' pictures: _Production drawing Pink Panther In â€œOlym-Pinksâ€, 1980.jpg_ and _Everybody Loves Eric Raymond 2006-01-11, The GPL3 according toâ€¦.jpg_.
 And the killer argument: there is an encoding well supported by your UNIX filesystems and your OS: this is called UTF-8.
 If you use UTF-8, you can mount a NTFS filesystem (which internally stores filenames in UTF-16) in UTF-8, and so have directly compatible filenames.

Now, your method would be useful in this case to convert FAT32 filenames.


```
#!/bin/sh
ENCODING_SOURCE=iso-8859-1
#To import Windows FAT32, use instead: ENCODING_SOURCE=cp1252
ENCODING_TARGET=utf-8

[ ${#} -eq 0 ] && {
  echo "usage: ${0##*/} FILE|DIRECTORY"
  exit 0
}
for FILE in "${@}"
do
  NEWNAME = `iconv "${FILE} -s -c -f ${ENCODING_SOURCE} -t ${ENCODING_TARGET}//TRANSLIT`
  if [ -z "${NEWNAME}" ]
  then
    echo "Can't rename ${FILE}"
  else
    mv "${FILE}" "${NEWNAME}"
  fi
done
```

It could also be used to keep characters your encoding should support, like Ã© or ÃŸ with ENCODING_SOURCE=cp1252 and ENCODING_TARGET=cp437 (if you use cons25 encoding).

iconv with use transliteration to convert any character not existing in target encoding according state of art admitted rules:

```
A origem da povoaÃ§Ã£o de Pereira parece estar ligada Ã s vicâ€¦.pdf (UTF-8, original)
A origem da povoaâ–’~ao de Pereira parece estar ligada â–’s vic....pdf (cp437, for cons25)
A origem da povoaÃ§~ao de Pereira parece estar ligada Ã s vic....pdf (converted back in UTF-8, this bulletin board encoding)
```

*Note:* There are two ports, converters/libiconv and converters/iconv. You probably already have libiconv installed, and probably with this option enabled ([X] EXTRA_ENCODINGS). If you have to install one and choose converter/iconv instead converter/libiconv, don't forget to install also converter/iconv-extra port and to note your binary will be "biconv" to avoid conflicts.


----------



## vermaden (Jul 27, 2012)

@Dereckson

Thank You for Your arguments, I will try to address them below.



> I don't like your solution, as it creates more problems than it solves.


It solves problems for me, but I do not agree that this is the best way to solve others' people encoding problems.



> [*] The solution doesn't solve the problem you announce it solved (FAT32/NTFS -> UNIX filesystem file moves).


I use it to rename files that are still 'valid', ofter when copying from FAT32/NTFS with different encoding then neede mounted, files will copy with 'bad' characters. I was thinking generally about issues with transferring files between FAT/NTFS and UNIX filesystems, not directly about FAT/NTFS -> UNIX migration.



> This method shows disdain to your international users: their glyphs are't allowed on your system.


I personally disdain MY national language/characters and think that they are harm/dangerous in filenames and also change them. I haven't thought about changing OTHER people filenames with that, only mine.



> The script doesn't care about proper transliteration. For example, ÃŸ should be replaced by ss (like s0=" | tr 'ÃŸ' 'ss' ").


I have read about 'ÃŸ' in Wikipedia, but, for simplicity I used only one 's', the script is editable and You can make it to change 'ÃŸ' to 'ss' instead of 's'. By definition/language rules, 'ÃŸ' is a 'ss' representation in one character, but I do not care (yes, its my ignorance) how *strong* is this 's', its still an 's'.

By the way, to make it work, You will have to change it like that (tr will not work):

```
[color="Red"]-s0=" | tr 'ÃŸ' 'ss' "[/color]
[color="Lime"]+s0=" | sed s/'ÃŸ'/'ss'/g "[/color]
```



> [*] There is a vocabulary issue, letting know you've some progress to do (or you don't really care) about l10n. For example, a language doesn't match a country, so â€œnational charactersâ€ doesn't mean anything. You even need non ASCII characters in English too.


My knowledge about l10n (and i18n) is limited, I did not dig that topic, I just wanted to solve the problem, and as tiem has passed I first created that script only with characters from my native language, then added all other possible characters, that will make my life easier.



> And the killer argument: there is an encoding well supported by your UNIX filesystems and your OS: this is called UTF-8.
> Great, but does FreeBSD console is fully UTF-8? Nope. Is everything in computing UTF-8 compatible? Nope. Until then I will translate 'national' [*] characters to english harmless ones.
> 
> [*] yes I remember that You mentioned that this naming convention is not valid, but its what best describes that issue for me
> ...


Will it rename the filenames as my script does (removing all national characters?), if yes, then maybe my scripts is useless and there is far better tool to do that?

Regards,
vermaden


----------



## vermaden (Jul 29, 2012)

@Dereckson

I just tried using iconv, it translates with 'additional characters, which is unacceptable:


```
% echo áºƒÅµáº…Ã¿Ã½á»³Å·Å¾Å¼Åº | iconv -c -f utf-8 -t iso-8859-1//TRANSLIT 
ï¿½w^w"wï¿½ï¿½`y^yzzï¿½z
```

While my toascii.sh script does the job and translates 'áºƒÅµáº…Ã¿Ã½á»³Å·Å¾Å¼Åº' into 'wwwyyyyzzz'.

Here is the latest version, with more characters:

toascii.sh

```
#! /bin/sh

[ ${#} -eq 0 ] && {
  echo "usage: ${0##*/} FILE|DIRECTORY"
  exit 0
}

a0=" | tr 'Ã ' 'a' "; A0=" | tr 'Ã€' 'A' ";
a1=" | tr 'Ã¡' 'a' "; A1=" | tr 'Ã' 'A' ";
a2=" | tr 'Ã¢' 'a' "; A2=" | tr 'Ã‚' 'A' ";
a3=" | tr 'Ã¤' 'a' "; A3=" | tr 'Ã„' 'A' ";
a4=" | tr 'Äƒ' 'a' "; A4=" | tr 'Ä‚' 'A' ";
a5=" | tr 'Ã£' 'a' "; A5=" | tr 'Ãƒ' 'A' ";
a6=" | tr 'Ã¥' 'a' "; A6=" | tr 'Ã…' 'A' ";
a7=" | sed s/'Ã¦'/'ae'/g "; A7=" | sed s/'Ã†'/'AE'/g ";
a8=" | tr 'É' 'a' "; A8=" | tr 'â±¯' 'A' ";
a9=" | tr 'Ä…' 'a' "; A9=" | tr 'Ä„' 'A' ";
aA=" | tr 'Ä' 'a' "; AA=" | tr 'Ä€' 'A' ";
aB=" | tr 'Äƒ' 'a' "; AB=" | tr 'Ä‚' 'A' ";
aC=" | tr 'ÇŸ' 'a' "; AC=" | tr 'Çž' 'A' ";
aD=" | sed s/'Ç½'/'ae'/g "; AD=" | sed s/'Ç¼'/'AE'/g ";
b0=" | tr 'á¸ƒ' 'b' "; B0=" | tr 'á¸‚' 'B' ";
c0=" | tr 'Ã§' 'c' "; C0=" | tr 'Ã‡' 'C' ";
c1=" | tr 'Ä‡' 'c' "; C1=" | tr 'Ä†' 'C' ";
c2=" | tr 'Ä' 'c' "; C2=" | tr 'ÄŒ' 'C' ";
c3=" | tr 'Ä‹' 'c' "; C3=" | tr 'ÄŠ' 'C' ";
d0=" | tr 'Ä' 'd' "; D0=" | tr 'ÄŽ' 'D' ";
d1=" | tr 'Ã°' 'd' "; D1=" | tr 'Ã' 'D' ";
d2=" | tr 'á¸‘' 'd' "; D2=" | tr 'á¸' 'D' ";
d3=" | tr 'Ä' 'd' "; D3=" | tr 'ÄŽ' 'D' ";
d4=" | tr 'á¸‹' 'd' "; D4=" | tr 'á¸Š' 'D' ";
d5=" | tr 'Ä‘' 'd' "; D5=" | tr 'Ä' 'D' ";
d6=" | tr 'Ã°' 'd' "; D6=" | tr 'Ã' 'D' ";
d7=" | sed s/'Ç†'/'dz'/g "; D5=" | sed s/'Ç„'/'DZ'/g ";
d8=" | sed s/'Ç³'/'dz'/g "; D6=" | sed s/'Ç±'/'DZ'/g ";
e0=" | tr 'Ã©' 'e' "; E0=" | tr 'Ã‰' 'E' ";
e1=" | tr 'Ã¨' 'e' "; E1=" | tr 'Ãˆ' 'E' ";
e2=" | tr 'Ãª' 'e' "; E2=" | tr 'ÃŠ' 'E' ";
e3=" | tr 'Ã«' 'e' "; E3=" | tr 'Ã‹' 'E' ";
e4=" | tr 'Ä™' 'e' "; E4=" | tr 'Ä˜' 'E' ";
e5=" | tr 'Ä›' 'e' "; E5=" | tr 'Äš' 'E' ";
e6=" | tr 'É›' 'e' "; E6=" | tr 'Æ' 'E' ";
e7=" | tr 'É™' 'e' "; E7=" | tr 'Æ' 'E' ";
e8=" | sed s/'Å“'/'oe'/g "; E8=" | sed s/'Å’'/'OE'/g ";
e9=" | tr 'Ä“' 'e' "; E9=" | tr 'Ä’' 'E' ";
eA=" | tr 'Ä•' 'e' "; E9=" | tr 'Ä”' 'E' ";
eB=" | tr 'Ä—' 'e' "; E9=" | tr 'Ä–' 'E' ";
e9=" | tr 'Ê’' 'e' "; E9=" | tr 'Æ·' 'E' ";
e9=" | tr 'Ç¯' 'e' "; E9=" | tr 'Ç®' 'E' ";
f0=" | tr 'á¸Ÿ' 'f' "; F0=" | tr 'á¸ž' 'F' ";
f1=" | tr 'Æ’' 'f' "; F1=" | tr 'Æ‘' 'F' ";
g0=" | tr 'Çµ' 'g' "; G0=" | tr 'Ç´' 'G' ";
g1=" | tr 'Ä£' 'g' "; G1=" | tr 'Ä¢' 'G' ";
g2=" | tr 'Ç§' 'g' "; G2=" | tr 'Ç¦' 'G' ";
g3=" | tr 'Ä' 'g' "; G3=" | tr 'Äœ' 'G' ";
g4=" | tr 'ÄŸ' 'g' "; G4=" | tr 'Äž' 'G' ";
g5=" | tr 'Ä¡' 'g' "; G5=" | tr 'Ä ' 'G' ";
g6=" | tr 'Ç¥' 'g' "; G6=" | tr 'Ç¤' 'G' ";
h0=" | tr 'Ä¥' 'h' "; H0=" | tr 'Ä¤' 'H' ";
h1=" | tr 'Ä§' 'h' "; H1=" | tr 'Ä¦' 'H' ";
i0=" | tr 'Ã­' 'i' "; I0=" | tr 'Ã' 'I' ";
i1=" | tr 'Ã®' 'i' "; I1=" | tr 'ÃŽ' 'I' ";
i2=" | tr 'Ã¯' 'i' "; I2=" | tr 'Ã' 'I' ";
i3=" | tr 'Ã¬' 'i' "; I3=" | tr 'ÃŒ' 'I' ";
i4=" | tr 'Ä©' 'i' "; I4=" | tr 'Ä¨' 'I' ";
i5=" | tr 'Ä«' 'i' "; I5=" | tr 'Äª' 'I' ";
i6=" | tr 'Ä­' 'i' "; I6=" | tr 'Ä¬' 'I' ";
i7=" | tr 'Ä¯' 'i' "; I7=" | tr 'Ä®' 'I' ";
i8=" | tr 'Ä±' 'i' "; I8=" | tr 'I' 'I' ";
j0=" | tr 'Äµ' 'j' "; J0=" | tr 'Ä´' 'J' ";
k0=" | tr 'Ä¸' 'k' ";
k1=" | tr 'á¸±' 'k' "; K1=" | tr 'á¸°' 'K' ";
k2=" | tr 'Ä·' 'k' "; K2=" | tr 'Ä¶' 'K' ";
k3=" | tr 'Ç©' 'k' "; K3=" | tr 'Ç¨' 'K' ";
l0=" | tr 'Äº' 'l' "; L0=" | tr 'Ä¹' 'L' ";
l1=" | tr 'Ä¾' 'l' "; L1=" | tr 'Ä½' 'L' ";
l2=" | tr 'Å‚' 'l' "; L2=" | tr 'Å' 'L' ";
l3=" | tr 'Å€' 'l' "; L3=" | tr 'Ä¿' 'L' ";
l4=" | tr 'Ä¼' 'l' "; L4=" | tr 'Ä»' 'L' ";
m0=" | tr 'á¹' 'm' "; M0=" | tr 'á¹€' 'M' ";
n0=" | tr 'Ã±' 'n' "; N0=" | tr 'Ã‘' 'N' ";
n1=" | tr 'Åˆ' 'n' "; N1=" | tr 'Å‡' 'N' ";
n2=" | tr 'Å„' 'n' "; N2=" | tr 'Åƒ' 'N' ";
n3=" | tr 'Å‹' 'n' "; N3=" | tr 'ÅŠ' 'N' ";
n4=" | tr 'Å†' 'n' "; N4=" | tr 'Å…' 'N' ";
n5=" | tr 'Å‰' 'n' ";
o0=" | tr 'Ã´' 'o' "; O0=" | tr 'Ã”' 'O' ";
o1=" | tr 'Ã¶' 'o' "; O1=" | tr 'Ã–' 'O' ";
o2=" | tr 'Å‘' 'o' "; O2=" | tr 'Å' 'O' ";
o3=" | tr 'Ã²' 'o' "; O3=" | tr 'Ã’' 'O' ";
o4=" | tr 'Ã¸' 'o' "; O4=" | tr 'Ã˜' 'O' ";
o5=" | tr 'Ã³' 'o' "; O5=" | tr 'Ã“' 'O' ";
o6=" | tr 'Ãµ' 'o' "; O6=" | tr 'Ã•' 'O' ";
o7=" | tr 'Å' 'o' "; O7=" | tr 'ÅŒ' 'O' ";
o8=" | tr 'Å' 'o' "; O8=" | tr 'ÅŽ' 'O' ";
o9=" | tr 'Ã¸' 'o' "; O9=" | tr 'Ã˜' 'O' ";
oA=" | tr 'Ç¿' 'o' "; OA=" | tr 'Ç¾' 'O' ";
p0=" | tr 'á¹—' 'p' "; P0=" | tr 'á¹–' 'P' ";
r0=" | tr 'Å•' 'r' "; R0=" | tr 'Å”' 'R' ";
r1=" | tr 'Å™' 'r' "; R1=" | tr 'Å˜' 'R' ";
r2=" | tr 'Å—' 'r' "; R2=" | tr 'Å–' 'R' ";
s0=" | sed s/'ÃŸ'/'ss'/g ";
s1=" | sed s/'Î²'/'ss'/g "; S1=" | sed s/'Î’'/'SS'/g ";
s2=" | sed s/'Å¿'/'ss'/g "; S2=" | sed s/'ÃŸ'/'SS'/g ";
s3=" | tr 'Å' 's' "; S3=" | tr 'Åœ' 'S' ";
s4=" | tr 'ÅŸ' 's' "; S4=" | tr 'Åž' 'S' ";
s5=" | tr 'Å¡' 's' "; S5=" | tr 'Å ' 'S' ";
s6=" | tr 'Å›' 's' "; S6=" | tr 'Åš' 'S' ";
s7=" | tr 'á¹¡' 's' "; S7=" | tr 'á¹ ' 'S' ";
t0=" | tr 'Å¥' 't' "; T0=" | tr 'Å¤' 'T' ";
t1=" | tr 'Å£' 't' "; T1=" | tr 'Å¢' 'T' ";
t2=" | tr 'Å§' 't' "; T2=" | tr 'Å¦' 'T' ";
t3=" | tr 'Ã¾' 't' "; T3=" | tr 'Ãž' 'T' ";
u0=" | tr 'Ã¹' 'u' "; U0=" | tr 'Ã™' 'U' ";
u1=" | tr 'Ãº' 'u' "; U1=" | tr 'Ãš' 'U' ";
u2=" | tr 'Ã»' 'u' "; U2=" | tr 'Ã›' 'U' ";
u3=" | tr 'Ã¼' 'u' "; U3=" | tr 'Ãœ' 'U' ";
u4=" | tr 'Å¯' 'u' "; U4=" | tr 'Å®' 'U' ";
u5=" | tr 'Å±' 'u' "; U5=" | tr 'Å°' 'U' ";
u6=" | tr 'Å©' 'u' "; U6=" | tr 'Å¨' 'U' ";
u7=" | tr 'Å«' 'u' "; U7=" | tr 'Åª' 'U' ";
u8=" | tr 'Å­' 'u' "; U8=" | tr 'Å¬' 'U' ";
u9=" | tr 'Å³' 'u' "; U9=" | tr 'Å²' 'U' ";
w0=" | tr 'áº' 'w' "; W0=" | tr 'áº€' 'W' ";
w1=" | tr 'áºƒ' 'w' "; W1=" | tr 'áº‚' 'W' ";
w2=" | tr 'Åµ' 'w' "; W2=" | tr 'Å´' 'W' ";
w3=" | tr 'áº…' 'w' "; W3=" | tr 'áº„' 'W' ";
y0=" | tr 'Ã¿' 'y' "; Y0=" | tr 'Å¸' 'Y' ";
y1=" | tr 'Ã½' 'y' "; Y1=" | tr 'Ã' 'Y' ";
y2=" | tr 'á»³' 'y' "; Y2=" | tr 'á»²' 'Y' ";
y3=" | tr 'Å·' 'y' "; Y3=" | tr 'Å¶' 'Y' ";
z0=" | tr 'Å¾' 'z' "; Z0=" | tr 'Å½' 'Z' ";
z1=" | tr 'Å¼' 'z' "; Z1=" | tr 'Å»' 'Z' ";
z2=" | tr 'Åº' 'z' "; Z2=" | tr 'Å¹' 'Z' ";

Oco=" | sed s/,/./g";
Oh0=" | tr 'â€”' '-' ";
Oh1=" | tr 'â€“' '-' ";
Otm=" | sed s/'â„¢'/'TM'/g ";
Ore=" | tr 'Â®' 'R' ";
OdQ=" | tr -d '!' ";
Ob0=" | tr -d '[' "; OB0=" | tr -d ']' ";
Ob1=" | tr -d '(' "; OB1=" | tr -d ')' ";
Ob2=" | tr -d '{' "; OB2=" | tr -d '}' ";

Tr="${Tr} ${a0} ${a1} ${a2} ${a3} ${a4} ${a5} ${a6} ${a7} ${a8} ${a9} ${Aa}"
Tr="${Tr} ${Ab} ${Ac} ${Ad} ${b0} ${c0} ${c1} ${c2} ${c3} ${d0} ${d1} ${d2}"
Tr="${Tr} ${d3} ${d4} ${d5} ${d6} ${e0} ${e1} ${e2} ${e3} ${e4} ${e5} ${e6}"
Tr="${Tr} ${e7} ${e8} ${e9} ${eA} ${eB} ${eC} ${eD} ${f0} ${f1} ${g0} ${g1}"
Tr="${Tr} ${g2} ${g3} ${g4} ${g5} ${g6} ${h0} ${h1} ${i0} ${i1} ${i2} ${i3}"
Tr="${Tr} ${i4} ${i5} ${i6} ${i7} ${i8} ${j0} ${k0} ${k1} ${k2} ${k3} ${l0}"
Tr="${Tr} ${l1} ${l2} ${l3} ${l4} ${m0} ${n0} ${n1} ${n2} ${n3} ${n4} ${n5}"
Tr="${Tr} ${o0} ${o1} ${o2} ${o3} ${o4} ${o5} ${o6} ${o7} ${o8} ${o9} ${oA}"
Tr="${Tr} ${p0} ${r0} ${r1} ${r2} ${s0} ${s1} ${s2} ${s3} ${s4} ${s5} ${s6}"
Tr="${Tr} ${s7} ${t0} ${T1} ${T2} ${T3} ${u0} ${u1} ${u2} ${u3} ${u4} ${u5}"
Tr="${Tr} ${u6} ${u7} ${u8} ${u9} ${w0} ${w1} ${w2} ${w3} ${y0} ${y1} ${y2}"
Tr="${Tr} ${y3} ${z0} ${z1} ${z2}"

TR="${TR} ${A0} ${A1} ${A2} ${A3} ${A4} ${A5} ${A6} ${A7} ${A8} ${A9} ${AA}"
TR="${TR} ${AB} ${AC} ${AD} ${B0} ${C0} ${C1} ${C2} ${C3} ${D0} ${D1} ${D2}"
TR="${TR} ${D3} ${D4} ${D5} ${D6} ${E0} ${E1} ${E2} ${E3} ${E4} ${E5} ${E6}"
TR="${TR} ${E7} ${E8} ${E9} ${EA} ${EB} ${EC} ${ED} ${F0} ${F1} ${G0} ${G1}"
TR="${TR} ${G2} ${G3} ${G4} ${G5} ${G6} ${H0} ${H1} ${I0} ${I1} ${I2} ${I3}"
TR="${TR} ${I4} ${I5} ${I6} ${I7} ${I8} ${J0} ${K1} ${K2} ${K3} ${L0} ${L1}"
TR="${TR} ${L2} ${L3} ${L4} ${M0} ${N0} ${N1} ${N2} ${N3} ${N4} ${O0} ${O1}"
TR="${TR} ${O2} ${O3} ${O4} ${O5} ${O6} ${O7} ${O8} ${O9} ${OA} ${P0} ${R0}"
TR="${TR} ${R1} ${R2} ${S1} ${S2} ${S3} ${S4} ${S5} ${S6} ${S7} ${T0} ${T1}"
TR="${TR} ${T2} ${T3} ${U0} ${U1} ${U2} ${U3} ${U4} ${U5} ${U6} ${U7} ${U8}"
TR="${TR} ${U9} ${W0} ${W1} ${W2} ${W3} ${Y0} ${Y1} ${Y2} ${Y3} ${Z0} ${Z1}"
TR="${TR} ${Z2}"

Os="${Oh0} ${Oh1} ${Otm} ${Ore} ${Oco}"

Od="${Ob0} ${OB0} ${Ob1} ${OB1} ${Ob2} ${OB2} ${OdQ}"

for FILE in "${@}"
do
  ASCII="echo \"${FILE}\" ${TR} ${Tr} ${Os} ${Od}"
  mv "${FILE}" "$( eval ${ASCII} 2> /dev/null )"
done
```


----------



## mwatkins (Jul 30, 2012)

Perhaps consider a script in Python? Hooking in the file renaming is easy enough, here is the character normalization using the "normal form KD" decomposition/composition:


```
import unicodedata

def normalize(string):
    return unicodedata.normalize('NFKD', input_string).encode('ascii', 'ignore')

print(normalize("áºƒÅµáº…Ã¿Ã½á»³Å·Å¾Å¼Åº"))
```

Produces:

```
wwwyyyyzzz
```

There is a little more to it than this; UTF-8 encoded strings read from the console or file system must be decoded as Unicode bytestrings, so the code will grow by a few more characters here and there. I'm posting this to show the unicodedata module in Python has done a lot of legwork needed for tasks like this. I guess I'll need to round it out and provide a complete script to be in keeping with this thread. Stay tuned, will be back.


----------



## vermaden (Jul 30, 2012)

@mwatkins

Thanks for that great tip, I am gonna dig into that python normalization right away! 

*EDIT:*

I tried something like that:


```
#! /usr/bin/env python
# -*- coding: utf-8 -*

import unicodedata

def normalize(input_string):
    return unicodedata.normalize('NFKD', input_string).encode('ascii', 'ignore')

print normalize("Ã Ã€Ã¡ÃÃ¢Ã‚Ã¤Ã„ÄƒÄ‚Ã£ÃƒÃ¥Ã…Éâ±¯Ä…Ä„ÄÄ€ÄƒÄ‚ÇŸÇžá¸ƒá¸‚Ã§Ã‡Ä‡Ä†ÄÄŒÄ‹ÄŠÄÄŽÃ°Ãá¸‘á¸ÄÄŽá¸‹á¸ŠÄ‘ÄÃ°ÃÃ©Ã‰Ã¨ÃˆÃªÃŠÃ«Ã‹Ä™Ä˜Ä›ÄšÉ›ÆÉ™ÆÄ“Ä’Ä•Ä”Ä—Ä–Ê’Æ·Ç¯Ç®á¸Ÿá¸žÆ’Æ‘ÇµÇ´Ä£Ä¢Ç§Ç¦ÄÄœÄŸÄžÄ¡Ä Ç¥Ç¤Ä¥Ä¤Ä§Ä¦Ã­ÃÃ®ÃŽÃ¯ÃÃ¬ÃŒÄ©Ä¨Ä«ÄªÄ­Ä¬Ä¯Ä®Ä±IÄµÄ´Ä¸á¸±á¸°Ä·Ä¶Ç©Ç¨ÄºÄ¹Ä¾Ä½Å‚ÅÅ€Ä¿Ä¼Ä»á¹á¹€Ã±Ã‘ÅˆÅ‡Å„ÅƒÅ‹ÅŠÅ†Å…Å‰Ã´Ã”Ã¶Ã–Å‘ÅÃ²Ã’Ã¸Ã˜Ã³Ã“ÃµÃ•ÅÅŒÅÅŽÃ¸Ã˜Ç¿Ç¾á¹—á¹–Å•Å”Å™Å˜Å—Å–ÅÅœÅŸÅžÅ¡Å Å›Åšá¹¡á¹ Å¥Å¤Å£Å¢Å§Å¦Ã¾ÃžÃ¹Ã™ÃºÃšÃ»Ã›Ã¼ÃœÅ¯Å®Å±Å°Å©Å¨Å«ÅªÅ­Å¬Å³Å²áºáº€áºƒáº‚ÅµÅ´áº…áº„Ã¿Å¸Ã½Ãá»³á»²Å·Å¶Å¾Å½Å¼Å»ÅºÅ¹Ã¦Ã†Ç½Ç¼Ç†Ç„Ç³Ç±Å“Å’ÃŸÎ²Î’Å¿ÃŸâ„¢Â®![](){}")
```

... but:


```
% [B][color="Blue"]python python-toascii.sh[/color][/B]
Traceback (most recent call last):
  File "python-toascii.sh", line 9, in <module>
    print normalize("Ã Ã€Ã¡ÃÃ¢Ã‚Ã¤Ã„ÄƒÄ‚Ã£ÃƒÃ¥Ã…Éâ±¯Ä…Ä„ÄÄ€ÄƒÄ‚ÇŸÇžá¸ƒá¸‚Ã§Ã‡Ä‡Ä†ÄÄŒÄ‹ÄŠÄÄŽÃ°Ãá¸‘á¸ÄÄŽá¸‹á¸ŠÄ‘ÄÃ°ÃÃ©Ã‰Ã¨ÃˆÃªÃŠÃ«Ã‹Ä™Ä˜Ä›ÄšÉ›ÆÉ™ÆÄ“Ä’Ä•Ä”Ä—Ä–Ê’Æ·Ç¯Ç®á¸Ÿá¸žÆ’Æ‘ÇµÇ´Ä£Ä¢Ç§Ç¦ÄÄœÄŸÄžÄ¡Ä Ç¥Ç¤Ä¥Ä¤Ä§Ä¦Ã­ÃÃ®ÃŽÃ¯ÃÃ¬ÃŒÄ©Ä¨Ä«ÄªÄ­Ä®Ä±IÄµÄ´Ä¸á¸±á¸°Ä·Ä¶Ç©Ç¨ÄºÄ¹Ä¾Ä½Å‚ÅÅ€Ä¿Ä¼Ä»á¹á¹€Ã±Ã‘ÅˆÅ‡Å„ÅƒÅ‹ÅŠÅ†Å…Å‰Ã´Ã”Ã¶Ã–Å‘ÅÃ²Ã’Ã¸Ã˜Ã³Ã“ÃµÃ•ÅÅŒÅÅŽÃ¸Ã˜Ç¿Ç¾á¹—á¹–Å•Å”Å™Å˜Å—Å–ÅÅœÅŸÅžÅ¡Å Å›Åšá¹¡á¹ Å¥Å¤Å£Å¢Å§Å¦Ã¾ÃžÃ¹Ã™ÃºÃšÃ»Ã›Ã¼ÃœÅ¯Å®Å±Å°Å©Å¨Å«ÅªÅ­Å¬Å³Å²áºáº€áºƒáº‚ÅµÅ´áº…áº„Ã¿Å¸Ã½Ãá»³á»²Å·Å¶Å¾Å½Å¼Å»ÅºÅ¹Ã¦Ã†Ç½Ç¼Ç†Ç„Ç³Ç±Å“Å’ÃŸÎ²Î’Å¿ÃŸâ„¢Â®![](){}")
  File "python-toascii.sh", line 7, in normalize
    return unicodedata.normalize('NFKD', input_string).encode('ascii', 'ignore')
TypeError: must be unicode, not str
```


----------



## kpa (Jul 30, 2012)

You have to tell python that the string literal is unicode:

```
print normalize(u"Ã Ã€Ã¡ÃÃ¢Ã‚Ã¤Ã„Äƒ...
```

On python3 there is no such problem because all strings are unicode. Another reason to prefer python 3 over 2


----------



## vermaden (Jul 30, 2012)

Thanks, works like a charm! 

Time to 'dive into Python' ;p


----------



## kpa (Sep 12, 2012)

Simple one-liner for PKGNG. This prints out installed packages sorted in order of their installation times. Output is installation time formatted with current locale and the package name.

`$ pkg  query "%t %n-%v" | sort -n -k1 | while read timestamp pkgname; do echo "$(date -r $timestamp) $pkgname"; done`

This works only in bourne type shells.


----------



## SNK (Sep 28, 2012)

```
#!/bin/sh

if [ $# -eq 1 ] && [ $1 = "cron" ]
    then /bin/sleep $(/usr/bin/jot -r 1 0 3600)
fi

echo "  ~  1  ~   Updating the ports tree..."
/usr/sbin/portsnap fetch update || exit 1

echo "  ~  2  ~   Checking for missing dependencies..."
/usr/sbin/pkg check -d || exit 1

echo "  ~  3  ~   Checking for vulnerabilities..."
/usr/sbin/pkg audit -F

echo "  ~  4  ~   Cleaning old packages..."
/usr/sbin/pkg clean || exit 1

echo "  ~  5  ~   What to upgrade..."
/usr/sbin/pkg version -IvL \= || exit 1

echo "  ~  6  ~   What is available in the repositories..."
/usr/sbin/pkg update || exit 1
/usr/sbin/pkg upgrade -Lqn || exit 1

echo "  ~  7  ~   Messages from UPDATING..."
weekago=$( /bin/date -v-1w "+%Y%m%d" )
lastpkg=$( /bin/date -r $( /usr/sbin/pkg query "%t" | /usr/bin/sort -n | /usr/bin/tail -n1 ) "+%Y%m%d" )

if [ $weekago -lt $lastpkg ]
    then usedate=$weekago
    else usedate=$lastpkg
fi

/usr/sbin/pkg updating -d $usedate
```

Hereby a small update of DutchDaemon's script. This one uses the new pkg(8) tools.


----------



## johnd (Oct 16, 2012)

When it comes to programming/scripting IÂ´m a pretty newbie. But I try 
Here is a script that IÂ´m using occasionally:


```
#!/bin/sh -e

# mfetch - a wrapper to fetch(1)
# it mimics wget --input-file behaviour
# argument $1: inputlist
# optional argument $2: directory

unset PATH

# Handling traps
trap 'echo "Aborting on signal." >&2; exit 1;' INT TERM

# Checking arguments
[ $# -lt 1 ] && { echo "Usage: ${0##*/} inputlist [directory]" >&2; exit 1; }

# Checking / Creating directories as needed
[ ! -d $2 ] && /bin/mkdir -p $2

# Feed fetch with URLs from inputlist
while read i; do
    /usr/bin/fetch -q -o ${2:-./} $i
done <$1

exit 0
```


----------



## lockdoc (Nov 8, 2012)

Hi,
here is a nice script to show the temperature of all attached hard disks






[1]

It currently works with ata disks.
I have tried to include disks connected to a ciss raid controller, but I am not sure if it works as I do not have one. Could anyone with a ciss controller please check this out and give some feedback.

The source of the script is here
https://github.com/lockdoc/hddtemp/blob/master/hddtemp.sh

It requires root privileges and smartmontools to be installed.

[1] My SSD does not report the proper temperature, that's why it always displays 128


----------



## kpedersen (Nov 21, 2012)

The following script disables the fan if the temp is lower than 45 and then enables it again at 55.

I know this isn't a brilliant idea but for some reason my Thinkpad x61 keeps its fan running trying to reach a very low temperature. It becomes quite cold for my wrist and quite uncomfortable for my lap 

This will only work when using the acpi_ibm module.


```
#!/bin/sh

disable_fan()
{
  echo "disable"
  sysctl dev.acpi_ibm.0.fan=0
}

enable_fan()
{
  echo "enable"
  sysctl dev.acpi_ibm.0.fan=1
}

try_disable_fan()
{
  if [ `sysctl -n dev.acpi_ibm.0.fan` = 1 ]; then
    disable_fan
  fi
}

try_enable_fan()
{
  if [ `sysctl -n dev.acpi_ibm.0.fan` = 0 ]; then
    enable_fan
  fi
}

if [ `id -u` != 0 ]; then
  echo "Error: Must be root"
  exit 1
fi

while [ true ]; do

  HIGHEST_TEMP=0
  TEMPERATURES=`sysctl -n dev.acpi_ibm.0.thermal`

  for TEMP in $TEMPERATURES; do
    if [ $TEMP -gt $HIGHEST_TEMP ]; then
      HIGHEST_TEMP=$TEMP
    fi
  done

  if [ $HIGHEST_TEMP -gt 55 ]; then
    try_enable_fan
  elif [ $HIGHEST_TEMP -lt 45 ]; then
    try_disable_fan
  fi

  sleep 5

done
```


----------



## nickednamed (Dec 3, 2012)

This is the first script I've ever written. It's not that pretty, it isn't overly user friendly, and I borrowed [stole] a lot of it from taz - http://forums.freebsd.org/showpost.php?p=194445&postcount=5

It is based on taz's script but allows me to quickly set up different VirtualBox VMs without having to edit the script:


```
#!/bin/sh

#-----------------------------------------------------------------------
#CONFIG
#-----------------------------------------------------------------------

echo "Type name of new VM:" 
read vmName

echo "Type full path for new VM:"
read hdPath

echo "Type VM disk size in megabytes:"
read hdSize

echo "Type amount of RAM to use in megabytes:"
read ramSize

echo "Type amount of RAM for GPU to use in megabytes:"
read gpuRamSize

echo "Type VM OS Type:"
read osType

echo "Type full path to guest installtion media or ISO:"
read guestISO

echo "Type host network interface name:"
read nic

#create folder for virtual hard disk image
if [ ! -d $hdPath ]
then 
    mkdir $hdPath
fi

#-----------------------------------------------------------------------
#CREATE
#-----------------------------------------------------------------------

#create a new virtual hard disk image.
VBoxManage createhd --filename $hdPath/$vmName.vdi --size $hdSize

#create a new XML virtual machine definition file
VBoxManage createvm --name $vmName --ostype $osType --register

#add an IDE controller with a DVD drive attached, and the install ISO inserted into the drive. Set "--medium none" to detach all.
VBoxManage storagectl $vmName --name "IDE Controller" --add ide
VBoxManage storageattach $vmName --storagectl "IDE Controller" --port 0 --device 0 --type hdd --medium $hdPath/$vmName.vdi
VBoxManage storageattach $vmName --storagectl "IDE Controller" --port 1 --device 0 --type dvddrive --medium $guestISO

#set boot order
VBoxManage modifyvm $vmName --boot1 dvd --boot2 disk --boot3 none --boot4 none

#set I/O APIC support
VBoxManage modifyvm $vmName --ioapic on

#set the amount of RAM
VBoxManage modifyvm $vmName --memory $ramSize

#set the amount of RAM for virtual graphics card
VBoxManage modifyvm $vmName --vram $gpuRamSize

#set network mode(briged,NAT...)
VBoxManage modifyvm $vmName --nic1 bridged --bridgeadapter1 $nic

#enable USB support
VBoxManage modifyvm $vmName --usb on

#enable sound
VBoxManage modifyvm $vmName --audio oss --audiocontroller ac97
```

I decided not to make it too fancy, requiring user to write full paths because the default machine directory may vary from machine to machine.


----------



## lockdoc (Dec 7, 2012)

Hi,
here is another one that will let you create jails on a non-zfs filesystem (without creating it via snapshots) easily, including a couple of default config files (rc.conf, fstab, etc) and does also perform a couple of pre-checks (dir not empty, dir available, etc):
https://github.com/lockdoc/freebsd-tools/blob/master/create-jail.sh


----------



## bbzz (Dec 7, 2012)

Here are some really really simple ones I used before as a basis for some of my other more specific scripts;

This one just check online status using tcp connect; returns online/offline.

```
#!/bin/sh
result="offline"
for i in 1 2 3; do      
        /usr/local/bin/netcat -w 5 -z www.google.com 80 2>/dev/null
        if [ $? = "0" ]; then
    result="online"
                break
        fi
done
echo $result
```

This one uses above script; It checks every 5 min for external IP and compares with last stored IP in a file. If it changes, send me an email and store new IP as well as date of change. Over time you get a bunch of different IPs you ever used (if you aren't on static that is).


```
#!/bin/sh
test=`$HOME/bin/test-if-online`
if [ $test = "online" ]; then
        current_IP=`tail -1 /var/tmp/current_ip_address.tmp | awk '{print $3}'`
        new_IP=`/usr/local/bin/curl -s ifconfig.me/ip`
        if [ $current_IP != $new_IP ]; then
                current_index=`tail -1 /var/tmp/current_ip_address.tmp | awk '{print $1}'`
                new_index=`expr $current_index + 1`
                new_date=`date "+%Y-%m-%d_%H.%M"`
                echo "$new_index $new_date $new_IP" >> /var/tmp/current_ip_address.tmp
                # -- Send mail
                tail -1 /var/tmp/current_ip_address.tmp | /usr/local/sbin/ssmtp me@gmail.com
        fi
fi
```

This one for ports, doesn't need explaining

```
#!/bin/sh
#update
/usr/local/bin/svn update /usr/ports
#any new?
pkg version -o -l \< | sed 's/[ <]//g' | tee $HOME/newports.001
#any vulns?
pkg audit -F | tee /var/tmp/portaudit_report.tmp
#any new updating?
pkg updating -d $(date -j -f "%s" "$(pkg query -a %t | sort | tail -1)" "+%Y%m%d")
```

One liner that shows total amount used by zfs snapshots on whole pool (not sure if there's an actual command for this)


```
#!/bin/sh
echo "$(zfs get -t filesystem -r -H -p usedbysnapshots zpool | awk '{print $3}' | awk '{total = total + $1}END{print total}') \
        / 1024 / 1024 / 1024" | bc
```


----------



## naveenbeast (Dec 9, 2012)

Reinstalling FreeBSD and the ports and the updates can become a real pain in the ass. I wrote this script up to assist me with exactly that. This script makes clang the default compiler, applies optimizations to make.conf, installs updates via freebsd-update and updates the port tree with portsnap, installs xorg, i3 window manager, installs transmission, install firefox (or chromium), installs the linux base files, installs and sets up flash player 11, configure xorg, and configure rc.conf to enable hald,dbus and the linux compatibility layer. It also installs utilities like subversion, wget, nano, bash, portmaster and portupgrade. Tested on FreeBSD 9.1 RC3 install. 

fbsd_setup.sh

```
#!/bin/sh
#By Naveen Mathew of the year 1998! :p

echo 'Configuring make.conf ....'
#Lets get rid of God forsaken gcc...
echo 'Changing default compiler from gcc to clang llvm ....'
echo '#Use the clang llvm compiler instead of gcc' >> /etc/make.conf
echo 'CC=clang' >> /etc/make.conf
echo 'CXX=clang++' >> /etc/make.conf
echo 'CPP=clang-cpp' >> /etc/make.conf

#Here we start optimizing
echo 'Adding optimization flags ....'
echo ' ' >> /etc/make.conf
echo '#Optimizations' >> /etc/make.conf
echo 'CFLAGS=-O2 -pipe -fno-strict-aliasing' >> /etc/make.conf
echo 'COPTFLAGS=-O2 -pipe -funroll-loops -ffast-math -fno-strict-aliasing' >> /etc/make.conf
echo 'OPTIMIZED_CFLAGS=YES' >> /etc/make.conf
echo 'BUILD_OPTIMIZED=YES' >> /etc/make.conf
echo 'WITH_OPTIMIZED_CFLAGS=YES' >> /etc/make.conf
echo '#Compiler options and optimizations added by the Jarvian OS configuration script' >> 
/etc/make.conf

#Update the system and ports tree
echo 'Updating system via freebsd-update ....'
freebsd-update fetch install
echo 'Updating ports tree ....'
cd /usr/ports && portsnap fetch update

#Installation of applications
echo 'Installing basic GUI applications ....'
cd /usr/ports/x11/xorg && make BATCH=Yes install clean
cd /usr/ports/x11-wm/i3 && make BATCH=Yes install clean
cd /usr/ports/x11/dmenu && make BATCH=Yes install clean
cd /usr/ports/x11/i3status && make BATCH=Yes install clean

echo 'Installing utilities ....'
cd /usr/ports/devel/subversion && make BATCH=Yes install clean
cd /usr/ports/ftp/wget && make BATCH=Yes install clean
cd /usr/ports/editors/nano && make BATCH=Yes install clean
cd /usr/ports/shells/bash && make BATCH=Yes install clean
cd /usr/ports/ports-mgmt/portmaster && make BATCH=Yes install clean
cd /usr/ports/ports-mgmt/portupgrade && make BATCH=Yes install clean

echo 'Installing everyday applications ....'
cd /usr/ports/net-p2p/transmission25 && make BATCH=Yes install clean #Transmission25 because the 
other one is broken...
cd /usr/ports/multimedia/vlc && make BATCH=Yes install clean
#Choose either one. Or install both :p
#If you prefer Chromium, comment the Firefox line and uncomment the Chromium line
#cd /usr/ports/www/chromium && make BATCH=Yes install clean #Chromium line
cd /usr/ports/www/firefox && make BATCH=Yes install clean #Firefox line

#Install linux base files and flash
echo 'Installing and setting up Linux base files and flash ....'
cd /usr/ports/emulators/linux_base_f10 && make BATCH=Yes install clean
cd /usr/ports/www/nspluginwrapper && make BATCH=Yes install clean
cd /usr/ports/www/linux-f10-flashplugin11 && make BATCH=Yes install clean
mkdir /usr/local/lib/browser_plugins
cd /usr/local/lib/browser_plugins && ln -s 
/usr/local/lib/npapi/linux-f10-flashplugin/libflashplayer.so
echo ''
echo 'Activating linux module with kldload ....'
kldload linux
echo 'Installing flash player plugin for user ....'
nspluginwrapper -v -a -i
echo ''

#Configure installed programs
echo "Configuring Xorg ...."
echo ' ' >> /etc/rc.conf && echo '#Added by Jarvian OS configuration script" >> /etc/rc.conf
echo 'hald_enable="YES"' >> /etc/rc.conf
echo 'dbus_enable="YES"' >> /etc/rc.conf
echo 'linux_enable="YES"' >> /etc/rc.conf
Xorg -configure
cp ~/xorg.conf.new /etc/X11/xorg.conf

#Below is code for the future. You can just uncomment it and use it now though. It works.
#echo 'Configuring i3 window manager. Windows (Super) key is the default modifier'
#echo 'The config file is located in ~/.i3/config'
#mkdir ~/.i3
#cp jconfig/config ~/.i3/config
```


----------



## naveenbeast (Dec 10, 2012)

*Chromium in root mode*

Here is another script I use. Its for chromium to launch in root mode. Before launching the script, create a user with username chrome and everything else as default. Put whatever you want for full name. Then place this script in /usr/local/bin and just execute 'chrome-root' in a terminal.

*chrome-root*

```
#!/bin/sh
#Chrome with data dir execution 
#For root accounts

echo 'Launching Google Chrome for root ....'
chrome --user-data-dir=/home/chrome
```

*Put the code into a file called chrome-root and chmod 777 it. Then place it in /usr/local/bin and enjoy life. *


----------



## naveenbeast (Dec 18, 2012)

*Second revision of reinstall script.*

The second version of my initial reinstall script.
It now installs and configures nearly everything for a day to day FreeBSD use.
It also now provides to methods of installing packages. Pkg_add or Ports.
It also does a bunch of other stuff.
To install, just extract the attachment below and run the setup0.setup file.
It will do everything else. 
*P.S pkg_add is too outdated for my preference so I recommend ports by all chances.*
View attachment Blackfire.tar.gz


----------



## graudeejs (Dec 18, 2012)

naveenbeast said:
			
		

> The second version of my initial reinstall script.
> It now installs and configures nearly everything for a day to day FreeBSD use.
> It also now provides to methods of installing packages. Pkg_add or Ports.
> It also does a bunch of other stuff.
> ...



The fact that it copies (actually it would fail) hidden directory makes me suspicious about this scripts.
And while I looked briefly at source and it looks ok, I would never ever use it (because of style how it's "installed", not to mention it will modify every aspect of system).
If anyone want's to try out, I recommend you check entire source (looks safe, but you never know)


@naveenbeast, check how I solve app configuration problem:
https://github.com/graudeejs/dot.files
https://github.com/graudeejs/dot.vim
https://github.com/graudeejs/dot.fvwm
https://github.com/graudeejs/desktop (needs updating)

System config is different matter, and I won't discuss it here (don't have that much time).

P.S.
At first I thought your setup0.setup will prepare environment to install some root-kit. No joking.


----------



## Zare (Dec 18, 2012)

naveenbeast said:
			
		

> Reinstalling FreeBSD and the ports and the updates can become a real pain in the ass. I wrote this script up to assist me with exactly that. This script makes clang the default compiler, applies optimizations to make.conf, installs updates via freebsd-update and updates the port tree with portsnap, installs xorg, i3 window manager, installs transmission, install firefox (or chromium), installs the linux base files, installs and sets up flash player 11, configure xorg, and configure rc.conf to enable hald,dbus and the linux compatibility layer. It also installs utilities like subversion, wget, nano, bash, portmaster and portupgrade. Tested on FreeBSD 9.1 RC3 install.
> 
> fbsd_setup.sh
> 
> ...



-fno-stict-aliasing isn't an optimization. It will disable aliasing by type for C/C++ compiler. Aliasing by type actually optimizes, because it assumes that different type pointers won't point to same address. If you need this option for your programs, address the issue in the code. There are a lot of different examples for C, like simply using those pointers in union. 

IMHO, it's only safe to put these gcc flags in /etc/make.conf : -pipe (forces programs in compilation process to communicate via pipes rather than temporary files), -O[n] (optimization level). Be sure to check out what flags are automatically enabled by various optimization levels. Even -march should be set by CPUTYPE variable, not CFLAGS.

Actually, it's best to leave out CFLAGS completely for standard FreeBSD usage.


----------



## kpa (Dec 18, 2012)

You're asking for a lot of trouble by running www/chromium as root, please don't do that. Whatever problems you have with it that could be solved by running it as root, find a another safer solution.


----------



## jrm@ (Jan 3, 2013)

*mode-line script*

Here is a script that gives me the x11-wm/stumpwm mode-line below.







I'm very new to shell scripting, so there is likely a better way to do much of what I did.  Criticism is welcomed.  I hard coded a few things that are specific to my system (e.g. I know the network interfaces are either wlan0 or em0), but it shouldn't too difficult to adapt to different setups.  I also use net/ifstat to get the network traffic data, because I couldn't get it to work with netstat().

ml

```
see next post
```


----------



## jrm@ (Jan 4, 2013)

Take two. The io and istat scripts are no longer needed and the script processes die when you exit x11-wm/stumpwm.

ml.sh

```
#!/usr/bin/env sh

stump_pid=`pgrep -a -n stumpwm`

mem_tot=`awk '/real memory/ {print $4;exit}' /var/run/dmesg.boot`
mem_tot=$(( ${mem_tot}/1024/1024 ))

# while stumpwm is still running
while kill -0 $stump_pid > /dev/null 2>&1; do
	hn=`hostname -s`
	date=`date '+%a %b %e %H:%M:%S'`
	disk=`df -t ufs -h | awk 'END{print $3" "$2" "$4}'`
	set -- $disk; ds_usd=$1; ds_tot=$2; ds_avl=$3;
	ds_usd_val=${ds_usd%?}; ds_usd_unt=${ds_usd#$ds_usd_val}
	ds_tot_val=${ds_tot%?}; ds_tot_unt=${ds_tot#$ds_tot_val}
	ds_avl_val=${ds_avl%?}; ds_avl_unt=${ds_avl#$ds_avl_val}
	io=`iostat -x -w2 -c2 ada0 | awk 'END{print $4" "$5}'`
	set -- $io; dr=$1; dw=$2
	net=
	if ifconfig wlan0 2> /dev/null | grep -q inet; then
		ifn="wlan0"
		net=`/usr/local/bin/ifstat -i wlan0 1 1 | awk 'END{print $1" "$2}'`
	elif ifconfig em0 | grep -q inet; then
		ifn="em0"
		net=`/usr/local/bin/ifstat -i em0 1 1 | awk 'END{print $1" "$2}'`
	fi
	[ -z "$net" ] || { set -- ${net}; if_dl=$1; if_ul=$2; }
	sysctl=`sysctl -n dev.cpu.0.freq hw.acpi.thermal.tz0.temperature\
    hw.acpi.battery.life hw.acpi.battery.state hw.pagesize\
    vm.stats.vm.v_inactive_count vm.stats.vm.v_free_count\
    vm.stats.vm.v_cache_count`;
	set -- $sysctl; cpu_freq=$1; cpu_tmp=${2%?}; bat_lf=$3; bat_st=$4;
	page_siz=$5; inct_cnt=$6; free_cnt=$7; cach_cnt=$8
	mem_use=$(( ${mem_tot}-(${inct_cnt}+${free_cnt}+${cach_cnt})*${page_siz}/1024/1024 ))
	vol=`mixer -s vol | sed 's/vol [0-9]*://'`
	ML="^[^B^7*$hn^] ^[^8*C^] %4d^[^9*MHz^] ${cpu_tmp}^[^9*C^] ^[^8*M^]\
 %4d^[^9*M^]/${mem_tot}^[^9*M^] ^[^8*D^] ${ds_usd_val}^[^9*${ds_usd_unt}^]/\
${ds_tot_val}^[^9*${ds_tot_unt}^] ${ds_avl_val}^[^9*${ds_avl_unt}^] %8.1f^[^9*K/s^] %8.1f^[^9*K/s^]"
	[ -z "${net}" ] || ML="${ML} ^[^8*$ifn^] %6.1f^[^9*K/s^] %6.1f^[^9*K/s^]"
	ML="${ML} ^[^8*B^] ${bat_lf}"
	if [ ${bat_st} = '0' ] || [ ${bat_st} = '2' ]; then
		ML="${ML}^[^9*-^]"
	else
 		ML="${ML}^[^9*+^]"
	fi
	ML="${ML} ^[^8*V^] ${vol} | ^[^B^7*${date}^]"
	if [ -z "${net}" ]; then
		printf "$ML" ${cpu_freq} ${mem_use} ${dr} ${dw} > /tmp/ml-info.txt
	else
		printf "$ML" ${cpu_freq} ${mem_use} ${dr} ${dw} ${if_ul} ${if_dl} > /tmp/ml-info.txt
	fi
done
```


----------



## jrm@ (Jan 5, 2013)

*script to start/stop wireless connections*


```
#!/usr/bin/env sh

# set this to your wireless interface
wl_if=iwn0

# Usage: ws [start <ssid> | stop | list]

if [ -z $wl_if ]; then
	printf "wl_if is not set to the wireless interface.\n"
	exit
fi

extra() { printf "Extra arguments are being ignored.\n"; }

stop_ws()
{ 
	ifconfig wlan0 destroy
	printf "wlan0 destroyed\n"
}

usage() { printf "Usage: ws [start <ssid> | stop | list]\n"; exit; }

[ $# -eq 0 ] && usage

if [ $1 = 'start' ]; then
	[ $# -lt 2 ] && usage
	[ $# -gt 2 ] && extra
	ifconfig wlan0 > /dev/null 2>&1 && stop_ws
	ifconfig wlan0 create wlandev ${wl_if}
	ifconfig wlan0 ssid $2
	if !(grep -q "^[[:space:]]*ssid=['\"'']\?$2['\"'']"\
 /etc/wpa_supplicant.conf); then
		printf "Adding an entry for $2 in /etc/wpa_supplicant...\n"
		stty -echo
		read -p "Passphrase: " ps_phr
		stty echo
		printf "\n** If password is incorrect, you have to fix\
 /etc/wpa_supplicant.conf before running "
		printf `basename $0`; printf " again. **\n"
		printf "\nnetwork={\n\tssid=\"$2\"\n\tpsk=\"${ps_phr}\"\n}\n" >>\
 /etc/wpa_supplicant.conf
	fi
	wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf
	printf "Associating with $2"
	while !(ifconfig wlan0 | grep -q associated); do
		printf "."
		sleep 1
	done
	printf "\nAssociated to $2\nFlushing route...\nCalling dhclient...\n"
	dhclient wlan0
	route change default -ifp wlan0
elif [ $1 = 'stop' ]; then
	[ $# -gt 1 ] && extra
	if ifconfig wlan0 > /dev/null 2>&1; then stop_ws
	else printf "The interface wlan0 does not exist.\n"
	fi
elif [ $1 = 'list' ]; then
	[ $# -gt 1 ] && extra
	ifconfig wlan0 > /dev/null 2>&1 || ifconfig wlan0 create wlandev ${wl_if}
	ifconfig wlan0 | grep -q 'status: associated' || ifconfig wlan0 up
	ifconfig wlan0 list scan
else
	usage
fi
```


----------



## Michael-Sanders (Feb 9, 2013)

Just discovered this, very handy (please excuse if its a repeat):


```
# obtain console screen width/height

w=$(tput cols)   # width
h=$(tput lines)  # height
x=$(expr $w / 2) # 1/2 width
y=$(expr $h / 8) # 1/8 height, etc...
```


----------



## wblock@ (Feb 9, 2013)

"Arithmetic expansion" can be used to avoid needing expr(1):

```
w=$(tput cols)   # width
h=$(tput lines)  # height
x=$((w / 2))
y=$((h / 8))
```


----------



## Michael-Sanders (Feb 9, 2013)

ahh!


----------



## bkouhi (Feb 15, 2013)

This simple script allow you to surf in ports tree and discover wonderful applications by reading pkg-descr:



```
#!/bin/sh
trap 'exit 0' 2

for i in $1/*
do
  if [ -d $i ] ; then
       cd $i
       clear
       echo -e "Name: $i\n"
        if [ -f pkg-descr ]; then
               less pkg-descr
        else
               echo -e "pkg-descr not found!\n"
        fi
        cd ..
  fi
done
```

Usage:
`% ./script /usr/ports/category`

To read next pkg-descr just press *q*, to quit the program press *CTRL+C*.
HTH


----------



## Michael-Sanders (Feb 16, 2013)

Very nifty script. =)

(Just thinking aloud here) would be handy if the end user could install a given package/port using your idea. Something like:


```
[color="Red"]<pseudo-code>[/color]

dialog --yesno --title "Install $PKG_NAME?" "$PKG_DESCR" $HEIGHT $WIDTH
[ $? -eq 0 ] && func_add_pkg $PKG_NAME || func_next_routine

[color="Red"]</pseudo-code>[/color]
```


----------



## jb_fvwm2 (Feb 16, 2013)

I once cat-ed together all the pkg-descr in a category or two so I could read them all at once; though had to script something up in a wrapper to put the port pwd below or above each snippet (file), so one could ascertain the port one was reading of... that was many years ago though.


----------



## Beastie (Feb 18, 2013)

Instead of decoding URL hex codes manually or relying on JavaScript-based online decoders, you can use the following one liner:

```
#!/bin/sh

echo "$1" | sed 's/%24/$/g;s/%26/\&/g;s/%2B/+/g;s/%2C/,/g;s/%2F/\//g;s/%3A/:/g;s/%3B/\;/g;s/%3D/=/g;s/%3F/?/g;s/%40/@/g;'
```
Example:

```
urldec.sh 'http%3A%2F%2Fforums.freebsd.org%2Fshowthread.php%3Ft%3D737'
```
(sorry for the second *code* tag, but the URL is not displayed properly in a *cmd* tag)


----------



## graudeejs (Mar 8, 2013)

Remove all gems:

```
$ gem list | awk '{print $1}' | xargs -I '%' -n 1 gem uninstall '%' -q -a -I
```


----------



## jb_fvwm2 (Mar 8, 2013)

Apologies if this is a repost. I have several directories each containing .tbz which unfortunately accumulate several versions of each without an easy method of parsing out the extra ones.  This week discovering that

```
bsddiff /dir1 /dir2
```
enables easy copy to-fro so that both are in sync, the only remaining task is to delete the older versions.
Two ports necc. for the following...

```
/usr/local/bin/gnuls -oSr | sort -k 4 | sort -k 8 | /usr/local/bin/lookat
```
[two xterm/screen/tmux/or the first .tbz directory ]
[ then the delete is already in history for the next .tbz  directory ]
...after the following is complete [If I've explained it adequately]

That is in one xterm. In the first .tbz  directory, parsing down thru the lookat  in one terminal, one can construct a long delete-older /bin/rm -v  line in a different  xterm/tmux/screen  [...and recall it from history to delete from any/all the additional tbz
directories.] [Very handy here, where a thumbdrive also is a repository for them.]  I
had thought of constructing a perl equivalent, but the certainty of knowing that the
task is done without error at the command line is worth the additional time to 
delete manually, at least for now... [Someday... pkg_info for example wants to unextract the .tbz to find its origin, making the process somewhat
too costly in CPU time...]

This is also useful if one wishes to purge older distfiles from /usr/ports/distfiles, (just one instance though) though usually one may not need to do that often [and it should then be repeated in /usr/ports/distfiles/gnome2 etc.]


----------



## graudeejs (Mar 9, 2013)

Beastie said:
			
		

> Instead of decoding URL hex codes manually or relying on JavaScript-based online decoders, you can use the following one liner:
> 
> ```
> #!/bin/sh
> ...



Here's a much better ruby script

```
#!/usr/bin/env ruby

require 'cgi'

ARGV.each do |encoded_url|
  puts CGI::unescape(encoded_url)
end
```


----------



## vermaden (Mar 9, 2013)

Beastie said:
			
		

> Instead of decoding URL hex codes manually or relying on JavaScript-based online decoders, you can use the following one liner:
> 
> ```
> #!/bin/sh
> ...



You may want to decode all possible characters:
http://sourceforge.net/apps/trac/shweb/browser/trunk/shweb/shweb_urldec


```
s/%25/%/g
s/%20/ /g
s/%09/	/g
s/%21/!/g
s/%22/"/g
s/%23/#/g
s/%24/\$/g
s/%26/\&/g
s/%27/'/g
s/%28/(/g
s/%29/)/g
s/%2a/\*/g
s/%2b/+/g
s/%2c/,/g
s/%2d/-/g
s/%2e/\./g
s/%2f/\//g
s/%3a/:/g
s/%3b/;/g
s/%3e/>/g
s/%3f/?/g
s/%40/@/g
s/%5b/\[/g
s/%5c/\\/g
s/%5d/\]/g
s/%5e/\^/g
s/%5f/_/g
s/%60/`/g
s/%7b/{/g
s/%7c/|/g
s/%7d/}/g
s/%7e/~/g
```


----------



## graudeejs (Mar 9, 2013)

vermaden said:
			
		

> You may want to decode all possible characters:
> http://sourceforge.net/apps/trac/shweb/browser/trunk/shweb/shweb_urldec
> 
> 
> ...



These are not All possible characters (this is small and very common subset of characters)


----------



## vermaden (Mar 9, 2013)

graudeejs said:
			
		

> These are not All possible characters (this is small and very common subset of characters)



But have dependence only on POSIX sed/sh, You do not need to have whole Ruby to do that 

Its the same reason I use portmaster instead of (IMHO a lot overrated) portupgrade.


----------



## graudeejs (Mar 9, 2013)

That's true. I just wanted to point out that it doesn't cover all characters (unlike you stated)*.*


----------



## graudeejs (Mar 10, 2013)

This night I was compiling LibreOffice. By one o'clock it still wasn't finished.
I didn't want computer to stay up all night, so I wrote this little script:


```
#!/bin/sh
while [ "`uptime | awk 'BEGIN {FS=","} {print $5}' | sed 's/ //g'`" != '0.00' ]; do
  sleep 300
  echo wait
done
# wait 10 more minutes
sleep 600
shutdown -p now
```

It waits until load average for 15 minutes is 0.00, then waits another 10 minutes and shuts down PC.

You need to have your system configured to be able to shutdown pc, or run this script as root.

P.S.
It worked great and PC turned off at 3:27


----------



## Carpetsmoker (Mar 11, 2013)

Why not just `make install; shutdown`?

In addition, your command can be simplified to:
``uptime | cut -d, -f5 | tr -d ' '``

Useless use of awk, sed, cat, and * should be punishable by repeated beatings.


For extra code golf points, here's the entire thing as short as I can make it on a single line:
`f() { [ $(uptime | cut -d, -f5 = ' 0.00' ] && sleep 600 && halt -p || echo wait && sleep 300 && f;} f`


----------



## graudeejs (Mar 12, 2013)

Carpetsmoker said:
			
		

> Why not just `make install; shutdown`?


I expected it will finish by 24:00 give or take.


In addition, your command can be simplified to:
``uptime | cut -d, -f5 | tr -d ' '``

Useless use of awk, sed, cat, and * should be punishable by repeated beatings.


For extra code golf points, here's the entire thing as short as I can make it on a single line:
`f() { [ $(uptime | cut -d, -f5 = ' 0.00' ] && sleep 600 && halt -p || echo wait && sleep 300 && f;} f`

I never used cut before, I'll take that into account in my next scripts.

Also I wrote this at about 1:00 o'clock (at night). It was a fast script to get things done.


Thanks for you input.


----------



## Carpetsmoker (Mar 13, 2013)

pkg_sanity

It does some basic sanity checks. It checks:
- for old FreeBSD binaries (ie. FreeBSD 8 binaries)
- for unresolvable shared libraries
- missing and/or leftover files in LOCALBASE

It doesn't:
- support pkgng (yet... I have no experience with pkgng)
- have a brain. Think before you act (see my signature).

I know there's already libchk, but that requires ruby, which I typically don't have installed.
There's also the `bsdadminscripts' port, but that's just confusing, it doesn't even install on my system, and if you need 464 lines of code to accomplish such a basic task, then IMHO you've put on the complicator's gloves. Also, I first wrote this a few years back before I learned of the bsdadminscripts.


----------



## vermaden (Mar 13, 2013)

Carpetsmoker said:
			
		

> It doesn't:
> - support pkgng (yet... I have no experience with pkgng)



The only reference to pkg_* tools I see in Your script ispkg_info -Wwhich is handled in PKGng bypkg which, the output is the same:


```
% pkg_info -W /usr/local/bin/lynx
/usr/local/bin/lynx was installed by package lynx-2.8.7.2,1

% pkg which /usr/local/bin/midori
/usr/local/bin/midori was installed by package midori-0.4.9_1
```

Also check this for 'mapping' between legacy *pkg_** and *PKGng* tools:
https://wiki.freebsd.org/PkgPrimer


----------



## Carpetsmoker (Mar 13, 2013)

Thanks vermaden, I also do this to get all installed files:


```
grep -Ev '(^@|^\+)' | ${pkgdb}/*/+CONTENTS | sort -u > "${pkgfiles_tmpfile}"
```

Will `pkg info -l \*` work as expected?

Also, what's the proper way to detect pkgng usage?


----------



## vermaden (Mar 14, 2013)

" said:
			
		

> `version=$(uname -r | head -c 1)`


This will stop working when 10.0-RELEASE is out 

I would use this one:
`version=$(uname -r | cut -d '.' -f 1)`



			
				Carpetsmoker said:
			
		

> Thanks vermaden, I also do this to get all installed files:
> 
> 
> ```
> ...



Try that:
`% pkg info -l -a | grep '^/'`



			
				Carpetsmoker said:
			
		

> Also, what's the proper way to detect pkgng usage?




```
% ls -l /var/db/pkg
total 100946
-r--r--r--  1 root  wheel    719028 2013.03.14 03:02 auditfile
-rw-r--r--  1 root  wheel  47235072 2013.03.13 20:18 local.sqlite
-rw-r--r--  1 root  wheel  55085056 2013.03.04 22:51 repo.sqlite
```

So I would check like that:

```
if [ -f /var/db/pkg/local.sqlite ]
then
  # PKGng case
  :
else
  # legacy pkg_* case
  :
fi
```

You may also check if it works to be sure:

```
% sqlite3 /var/db/pkg/local.sqlite '.tables'
```

... or compare the number of pkg_info lines count output with pkg info lines count output ;p


----------



## kpa (Mar 14, 2013)

Carpetsmoker said:
			
		

> Also, what's the proper way to detect pkgng usage?



That's a tough one because the system may have both sets of tools installed at the same time and with valid databases.

Maybe just `make -V WITH_PKGNG` and see if the answer is "yes".


----------



## Carpetsmoker (Mar 14, 2013)

Thanks, I've updated the script so that it should work with pkgng.

For the record, I now use this to detect pkgng usage:

```
[ -f ${pkgdb}/local.sqlite ] && [ "X$(make -V WITH_PKGNG)" != "X" ]
pkgng=$?
```

This way, people who set the variable in /etc/make.conf but haven't initialized it yet will still be fine, and people who just tried it out but then unset the variable in /etc/make.conf (but still have the sqlite db) will also be fine.

(Checking if WITH_PKGNG is `yes' is not correct, since /ports/Mk/* check for .if defined(WITH_PKGNG), so setting it to `y', `42', `migratory coconut', etc. in /etc/make.conf or using -DWITH_PKGNG is all valid).




> version=$(uname -r | head -c 1)
> 
> This will stop working when 10.0-RELEASE is out
> 
> ...



Thank you for pointing out this rather silly mistake (*shame*).


----------



## vermaden (Mar 14, 2013)

kpa said:
			
		

> Maybe just `make -V WITH_PKGNG` and see if the answer is "yes".



Currently we have WITH_PKGNG in /etc/make.conf but as PKGNG will be the default You would not put anything to /etc/make.confjust the same as now with legacy pkg_* tools.


----------



## fullauto (Apr 29, 2013)

*Skelup.sh*

I wrote a small script a bit ago to check users dot files and keep them in sync with the /usr/share/skel dir. Many of my users hose their user directories, so I have this run every night at 0330 to ensure that all users dot files are the same...

Feel free to edit and use.  This is the first script I have ever written, so if you find anything that would make it easier/cleaner/better/safer, please don't be afraid to say something. I am always looking for constructive criticism.  


```
#!/usr/local/bin/bash

#######################################################################
#
# Written by: Me@mybox.net
# Purpose: Update usr dot files with updated skel dir
# Dependancies: None
# Revision Log: 1.0
#       3/17/13 - Started writting
#
#######################################################################

clear
DEBUG=0

SDIR="/usr/share/skel"
UDIR="/usr/home"
if [ "$DEBUG" -ge "1" ]; then
        printf "==> \$SDIR = %s" "$SDIR"
fi

usage ()
{
echo "Usage: skelup.sh [-d user directory] [-s skel dir]"
echo ""
echo "If no arguments are given user dir is set to: $UDIR"
echo "and skeleton dir is set to: $SDIR"
}

ERR=0
while getopts ":d:s:" OPT
do
case $OPT in
        :)
                echo "Option -$OPTARG requires an argument"
                ERR=1
                usage
                ;;
        \?)
                echo "Illegal options -$OPTARG"
                ERR=1
                usage
                ;;
        d)
                UDIR=$OPTARG
                ;;
        s)
                SDIR=$OPTARG
                ;;
esac
done

if [ $ERR -gt 0 ]; then
        echo "Options failed - exiting"
        exit 1
fi

if ! [ -z $UDIR ]; then
        echo "---> Checking for user dir sanity"
        sleep .5
        declare -a ETCU=($(cat /etc/passwd | grep -v '^#' | awk -F ":" '{print $1}'))
        FOUND=0
        for U in ${ETCU[@]}
        do
                if [ -e $UDIR/$U/.login ]; then
                        FOUND=$(( $FOUND + 1 ))
                fi
        done
        if [ $FOUND -ge 1 ]; then
                echo "Found $FOUND user directories out of ${#ETCU[@]} users in /etc/passwd"
                echo -n "$UDIR is a valid user dir - "; sleep .5; echo "PASSED"
                declare -a USERS=($(ls $UDIR))
        else
                echo "Didn't find ANY user directories in $UDIR - Exiting"
                exit 1
        fi
fi

echo "---> Checking for valid skeleton dir"
sleep .5
declare -a VS=($(ls $SDIR | grep '^dot.*'))

if ! [ -z ${VS[0]} ]; then
        echo -n "$SDIR is a valid skeleton dir - "; sleep .5; echo "PASSED"
        declare -a SFILES=(${VS[@]})
else
        echo "No valid dot files found in $SDIR - Exiting"
        exit 1
fi

echo "--------------------------------------------------------------------"
echo "---> Skeleton Dir:   $SDIR"
echo "---> User Dir:       $UDIR"
echo "--------------------------------------------------------------------"

sleep .5
echo "---> Checking for differences in User vs skel dir"

I=0
for U in ${USERS[@]}
do
        echo "------------- ${USERS[$I]} --------------"
        C=0
        for S in ${SFILES[@]}
        do
                STR=""
                STR="${SFILES[$C]}"
                FNAME="${STR:3}"
                DIF=$(diff -q $UDIR/${USERS[$I]}/$FNAME $SDIR/dot$FNAME)
                if ! [ -z "$DIF" ]; then
                        echo "$FNAME and dot$FNAME are DIFFERENT"
                        echo "---> Backing up user file as $FNAME-BAK"
                        cp $UDIR/${USERS[$I]}/$FNAME $UDIR/${USERS[$I]}/$FNAME-BAK
                        if [ -e $UDIR/${USERS[$I]}/$FNAME-BAK ]; then
                                echo "---> Backup successfull; Removing $FNAME"
                                rm $UDIR/${USERS[$I]}/$FNAME
                                cp $SDIR/dot$FNAME $UDIR/${USERS[$I]}/$FNAME
                                echo "---> Updating $FNAME with dot$FNAME"
                        else
                                echo "---> BACKUP DIDNT WORK - ABORTING"
                                break
                        fi
                fi
                C=$(( $C + 1 ))
        done
        I=$(( $I + 1 ))
        sleep .5
done

echo "======================================================================="
echo "|         ${#USERS[@]} users checked and updated with $SDIR            |"
echo "|     All users original files have been backed up as <file>-BAK      |"
echo "======================================================================="

exit 0
```


----------



## graudeejs (Apr 29, 2013)

That is, if a user updates his config, it's gone at 03:30. I wouldn't be happy.


----------



## kpa (Apr 29, 2013)

Small startup/re-attach script for sysutils/tmux. It sets up the SSH_AUTH_SOCK environment variable so that the ssh-agent(8) forwarding can be used in a re-attached session.

It's a bit of work in progress because I haven't yet been able to test if the clean-up using trap(1) is bullet-proof and what other signals I should catch.


```
#!/bin/sh

trap tmux-session-cleanup EXIT HUP

tmux-session-cleanup()
{
    if [ -L "${USERSOCKET}" ]; then
        echo "Removing ${USERSOCKET}"
        rm -f "${USERSOCKET}"
    fi
}

USERSOCKET="/tmp/.wrap_auth_sock-${USER}"

if [ -n "$TMUX" ]; then
    # Already in tmux session, do nada
    echo "Already in tmux session"
    exit 1
fi

# Set up ssh agent forwarding.

# Test if the symbolic link exists and is a link to a working socket.
if [ -L "${USERSOCKET}" ] && [ -e "${USERSOCKET}" ]; then
    echo "Refusing to overwrite existing link"
    exit 1
fi

if [ -n  "$SSH_TTY" ] && [ -n "${SSH_AUTH_SOCK}" ]; then
    ln -sf "$SSH_AUTH_SOCK" "${USERSOCKET}" # Create the symbolic link
    export SSH_AUTH_SOCK="$USERSOCKET" # Set SSH_AUTH_SOCK to the link
fi


TMUX_SESSION=$1

: ${TMUX_SESSION:="sshwrap"}

export STY="tmux-${TMUX_SESSION}"

tmux new-session -A -s "${TMUX_SESSION}"
```


I use this script as tmux-session.sh and I run it manually from a login shell.


----------



## teckk (May 2, 2013)

This post is for educational purposes only, to better understand how streaming media servers work. For anyone who is interested.

Playing web page media streams in a media player without a browser. I approached it in several different ways.

Some websites with streaming media content hide the stream location, and the media will only play from within a browser with JavaScript enabled, so the scripts on the page will run. Looking through the pages source can reveal a playlist for the stream. However some servers stream their media in small segments that are time stamped. The playlist for the stream changes every few seconds and it contain the media location with time stamped info. Such as this playlist.m3u8:

```
#EXTM3U
#EXT-X-TARGETDURATION:10
#EXT-X-ALLOW-CACHE:YES
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:1744929
#EXTINF:10.000,
http://path/to/segment1744929_128.ts?sd=10&rebase=
#EXTINF:10.000,
http://path/to/segment1744930_128.ts?sd=10&rebase=
#EXTINF:10.000,
http://path/to/segment1744931_128.ts?sd=10&rebase=
```
In order to play the stream with a media player from the server, you have to download the playlist, replace the playlist every 10 seconds, keep the media player playing that same named playlist, and if the player runs out of stream it will exit. This particular stream is .aac audio. The media streams in 160k segments every 10 seconds. Then there is a small lag from segment to segment. If the stream is directed to a named pipe or -, the audio stream will be interrupted every 10 seconds while a new segment is downloaded.

My solution is to stream the media to file, append the segments to file, let the stream cache for a time, then playing that file with the media player. Getting the playlist every 5 seconds, then `hash` every time and rejecting anything that was already done gives an uninterrupted stream to the media player. Saving the stream to file also gives you a copy for later listening.


```
#!/usr/local/bin/bash

PROGN="m3u2aac"

URI="http://path/to/the/playlist.m3u8"

	fetchFile() 
	{ 
	_MYTMPFILE=`mktemp -p /tmp ${PROGN}.XXXXXXXXXX` && 
	{
	while [ true ]
	do 
	wget -O "${_MYTMPFILE}" "${URI}"

		HASH=($(md5sum "${_MYTMPFILE}"))
		[ "${#PREVHASH}" -eq 0 -o "${PREVHASH}" != "${HASH[0]}" ] &&

	{ 
	mplayer -playlist "${_MYTMPFILE}" -dumpstream -dumpfile "${_MYTMPFILE}.aac" &&
	cat "${_MYTMPFILE}.aac" >> ~/path/audio.aac
	} &

		PREVHASH="${HASH[0]}"
	sleep 5
	done
	} 
 
	rm -f "${_MYTMPFILE}" "${_MYTMPFILE}.aac"
	} 

fetchFile &
sleep 20 &&
mplayer ~/path/audio.aac

exit 0
```
Change URI= to your playlist, or have the script ask for it.
This was a scripting learning exercise for me.

This works also without dumping to file, but you'll get interuptions in play.

```
#!/usr/local/bin/bash

playlist=$(mktemp)
dumpfile=$(mktemp)
trap 'rm -f -- "$playlist" "$dumpfile"' 0

while :
do
wget -O "$playlist" http://path/to/the/playlist.m3u8 &&
mplayer -playlist "$playlist" -dumpstream -dumpfile "$dumpfile" &&
cat "$dumpfile"
sleep 10
done | 
mplayer -
```

This will simply dump the stream to file.

```
#!/usr/local/bin/bash

cd ~/test
a=1
while [ "$a" ];do
rm playlist.m3u8
wget http://path/to/the/playlist.m3u8
mplayer -playlist playlist.m3u8 -dumpstream -dumpfile $a &&
sleep 10
cat $a >> audio.aac &&
rm $a
let a=a+1
done
```


----------



## lme@ (May 7, 2013)

kpedersen said:
			
		

> The following script disables the fan if the temp is lower than 45 and then enables it again at 55.
> 
> I know this isn't a brilliant idea but for some reason my Thinkpad x61 keeps its fan running trying to reach a very low temperature. It becomes quite cold for my wrist and quite uncomfortable for my lap
> 
> ...




Oh, that's nice. I wrote a similar script for Thinkpads. I'll post it later.


----------



## lme@ (Jul 21, 2013)

Now it's later 

Just a quick script I wrote for a friend whose Thinkpad fand was too noisy:


```
#!/bin/sh

# v0.2

# (C) 2013 Lars Engels <lars.engels@0x20.net>
#
#   BSD-style copyright and standard disclaimer applies.


sysctl="/sbin/sysctl"

check_interval=3

fan_max=7
fan_min=0


fan_level_mib="dev.acpi_ibm.0.fan_level"
#thermal_mib="dev.cpu.0.temperature"
thermal_mib="dev.acpi_ibm.0.thermal"
auto_control_mib="dev.acpi_ibm.0.fan"

level_1=40
level_2=45
level_3=50
level_4=55
level_5=60
level_6=65
level_7=70

print_verbose() {
	[ -n "${verbose}" ] && echo "$@"
}

enable_auto_control() {
	print_verbose "Enabling Fan auto control."
 	${sysctl} ${auto_control_mib}=1 2>/dev/null
}

disable_auto_control() {
	print_verbose "Disabling Fan auto control."
 	${sysctl} ${auto_control_mib}=0 2>/dev/null
}

get_fan() {
	${sysctl} -n ${fan_level_mib}
}

set_fan() {
	${sysctl} ${fan_level_mib}=${1} >/dev/null
}

exit_nomodule() {
	echo "No MIB ${auto_control_mib} found! Is acpi_ibm.ko not loaded?"
	exit 1
}

print_status() {
	${sysctl} -n ${thermal_mib} 2>/dev/null |
 	while read cpu_temp mpci_temp hdd_tmp gpu_tmp ibatt_temp ubatt_temp crap; do
        	echo "CPU:              ${cpu_temp}"
        	echo "Mini PCI Module:  ${mpci_temp}"
        	echo "HDD:              ${hdd_tmp}"
        	echo "GPU:              ${gpu_tmp}"
        	echo "Built-in battery: ${ibatt_temp}"
        	echo "UltraBay battery: ${ubatt_temp}"
		echo "Fan Level:        $(get_fan) of ${fan_max}"
	done
}

trap print_status INFO
trap enable_auto_control INT


[ "${1}" = "-v" ] && verbose=1

disable_auto_control || exit_nomodule

while sleep ${check_interval}; do
	cur_temp=$(${sysctl} -n ${thermal_mib} | cut -d" " -f1)

	if   [ ${cur_temp} -lt ${level_1} ]; then
		level=${fan_min}
	elif [ ${cur_temp} -lt ${level_2} ]; then
		level=1
	elif [ ${cur_temp} -lt ${level_3} ]; then
		level=2
	elif [ ${cur_temp} -lt ${level_4} ]; then
		level=3
	elif [ ${cur_temp} -lt ${level_5} ]; then
		level=4
	elif [ ${cur_temp} -lt ${level_6} ]; then
		level=5
	elif [ ${cur_temp} -lt ${level_7} ]; then
		level=6
	else
		level=7
	fi

	set_fan ${level}
	print_verbose "Temperature=${cur_temp};Fan-Level=${level}"
done
```


----------



## teckk (Aug 28, 2013)

If anyone can use this. A couple of scripts that I wrote for Google text to speech, and Google text to text translation. They work from shell and allow you to translate until you quit.

The text to speech script concatenates to $FILE.mp3 so you can make a single file out of 100 char max. segments. The text to text dumps the output to sdout, redirect to $FIlE if you want. You might want to take it easy on how many times a minute you hit their server.

Text to text

```
#! /usr/local/bin/bash

# Translate text using google. No google account needed.
# Requires curl, awk, iconv, html2text
# Language are:
# af ar az be bn bg bs ca cub zh-CN zh-TW cs cy da de en en_us en_gb en_au 
# el es et eu fa fi fr ga gl gu ht hi hmn hr hu hy is id it iw ja jw ka km 
# kn ko la lv lt mk mr ms mt no nl pl pt ro ru sr sk sl sq sw sv ta te th tl 
# tr uk ur vi yi

clear
OPTIONS="Input_Lang Output_Lang Enter_Text Translate Quit"
echo "Press Enter at any time to return to menu."
echo "Select an option:"
select opt in $OPTIONS; do

if [ "$opt" = "Quit" ]; then
clear
exit

elif [ "$opt" = "Input_Lang" ]; then
echo "Language options are:"
echo "en de fr es it" # Add languages here.
echo "What input language"
read ILAN

elif [ "$opt" = "Output_Lang" ]; then
echo "Language options are:"
echo "en de fr es it" # Add languages here.
echo "What ouput language"
read OLAN

elif [ "$opt" = "Enter_Text" ]; then
echo "Enter text"
read TEXT

elif [ "$opt" = "Translate" ]; then

result=$(curl -s -i --user-agent "" -d "sl=$ILAN" -d "tl=$OLAN" --data-urlencode "text=$TEXT" http://translate.google.com)
encoding=$(awk '/Content-Type: .* charset=/ {sub(/^.*charset=["'\'']?/,""); sub(/[ "'\''].*$/,""); print}' <<<"$result")

iconv -f $encoding <<<"$result" |  awk 'BEGIN {RS="</div>"};/<span[^>]* id=["'\'']?result_box["'\'']?/' | html2text

else
echo "Bad option"
fi; done
```

Text to voice

```
#! /usr/local/bin/bash

# Text to speech conversion using google text to voice. No google account needed.
# Requires wget
# 100 char. max. Output to "$NAME.mp3"
# Language are:
# af ar az be bn bg bs ca cub zh-CN zh-TW cs cy da de en en_us en_gb en_au 
# el es et eu fa fi fr ga gl gu ht hi hmn hr hu hy is id it iw ja jw ka km 
# kn ko la lv lt mk mr ms mt no nl pl pt ro ru sr sk sl sq sw sv ta te th tl 
# tr uk ur vi yi

clear
OPTIONS="Language Enter_Text Filename Translate Quit"
echo "Press Enter at any time to return to menu."
echo "Select an option:"
select opt in $OPTIONS; do

if [ "$opt" = "Quit" ]; then
clear
exit

elif [ "$opt" = "Language" ]; then
echo "Language options are:"
echo "en de fr es it" # Add languages here.
echo "What Language?"
read LNG

elif [ "$opt" = "Enter_Text" ]; then
echo "Enter text to translate to voice"
read WORDS

elif [ "$opt" = "Filename" ]; then
echo "Output file name?"
read NAME

elif [ "$opt" = "Translate" ]; then
URL="http://translate.google.com/translate_tts?tl=${LNG}&q="
wget -q -U Mozilla -O - "$URL""$WORDS" >> "$NAME".mp3

else
echo "Bad option"
fi; done
```


----------



## Carpetsmoker (Sep 1, 2013)

I do not appreciate wording being changed. So **** you and this `useful script'.


----------



## caimadur (Sep 1, 2013)

*cutleaves-ng*

I wrote a cutleaves script for PKGNG. It deletes packages, that are not needed as a dependency for other packages. Instead of asking you for every package, if you want to delete it (y|n) it gives you a list to edit. If not run as root, it uses sudo where needed.


```
#! /bin/sh

# cutleaves-ng

# pkg version option: -I index, -P ports, -R reposity catalogue
PVO="-I"
# change this if you wrote your own meta port
METAPORT="ports-mgmt/wanted-ports"

usage () {
     cat << EOF
Usage: $(basename $0) [option]

Delete interactively out-of-date-packages that are not required as a
dependency by other packages.

Options:
     -h       show this message
     -a       include up-to-date-packages
     -l FILE  log output to file

EOF
exit
}

ALL=
LOGFILE=/dev/null
while getopts 'ahl:' OPTION; do
     case $OPTION in
	  a)	ALL=YES;;
	  h)	usage;;
	  l)	LOGFILE=$OPTARG;;
	  *)	usage;;
     esac
done

if [ $(whoami) = root ]; then
     SUDO=
elif which sudo >/dev/null; then
     SUDO=sudo
else
     echo "Sorry." >&2
     exit 77
fi

echo "# List of packages to be deleted" >/tmp/$$leaves
echo "# To keep a package remove the line." >>/tmp/$$leaves
echo "# Type [F2] to register a package with wanted-ports(1)." >>/tmp/$$leaves
echo "# Type [F3] to see pkg info -f." >>/tmp/$$leaves

if [ "$ALL" == "YES" ]; then
     pkg query -e "%#r == 0 && %o != $METAPORT" %o >>/tmp/$$leaves
else
     pkg version $PVO -oL = | awk '{print $1}' >/tmp/$$update
     pkg query -e "%#r == 0 && %o != $METAPORT" %o | \
	  grep -xf /tmp/$$update >>/tmp/$$leaves 
fi

# don't want to run vim as root
if [ $SUDO ] && which vim >/dev/null; then
     vim "+map <F2> :! $SUDO wanted-ports -a <cWORD> <CR>" \
	  '+map <F3> :! pkg info -f <cWORD> \| more <CR>' /tmp/$$leaves
else
     ${EDITOR:-vi} /tmp/$$leaves
fi

# make sure user is sudoer before getting into trouble
if $SUDO true; then
     echo "$(basename $0) $(date)" >"$LOGFILE"
     echo >>"$LOGFILE"
     grep -v "^#" /tmp/$$leaves | xargs -n 1 $SUDO pkg delete -y | \
     	  tee -a "$LOGFILE"
     rm /tmp/$$leaves
else
     echo "Aborting. List is saved here: /tmp/$$leaves." >&2
fi
[ -f /tmp/$$update ] && rm /tmp/$$update 
exit 0
```


----------



## cpm@ (Sep 2, 2013)

*Google Text to Text Translation*

@teckk,

I have a problem with the iconv(1) conversion, despite it supporting the encoding charset ISO-8859-1 it throws the following error:

```
unsupportedrsion from ISO-8859-1
iconv: try 'iconv -l' to get the list of supported encodings
```

iconv(1) on BSD has:

```
[CMD]% iconv -l | grep ISO-8859-1[/CMD]
CP819 IBM819 ISO-8859-1 ISO-IR-100 ISO8859-1 ISO_8859-1 ISO_8859-1:1987 L1 LATIN1 CSISOLATIN1
ISO-8859-10 ISO-IR-157 ISO8859-10 ISO_8859-10 ISO_8859-10:1992 L6 LATIN6 CSISOLATIN6
ISO-8859-11 ISO8859-11 ISO_8859-11
ISO-8859-13 ISO-IR-179 ISO8859-13 ISO_8859-13 L7 LATIN7
ISO-8859-14 ISO-CELTIC ISO-IR-199 ISO8859-14 ISO_8859-14 ISO_8859-14:1998 L8 LATIN8
ISO-8859-15 ISO-IR-203 ISO8859-15 ISO_8859-15 ISO_8859-15:1998 LATIN-9
ISO-8859-16 ISO-IR-226 ISO8859-16 ISO_8859-16 ISO_8859-16:2001 L10 LATIN10
```

This is the full log of `bash -x google-translate.sh`

Any clue about what happens?

PS. I'm using the Citrus iconv encoding. See BSD-licensed libiconv in base system for more details.


----------



## kpa (Sep 2, 2013)

vermaden said:
			
		

> Currently we have WITH_PKGNG in /etc/make.conf but as PKGNG will be the default You would not put anything to /etc/make.confjust the same as now with legacy pkg_* tools.



Apparently ports-mgmt/portmaster has been doing this for a while now to test if PKGNG is used:

`pkg info pkg >/dev/null 2>&1 && use_pkgng=yes`

This will return error code !=0 properly and silently if there's only the interactive bootstrap /usr/sbin/pkg available.


----------



## teckk (Sep 3, 2013)

@cpu82

I don't know. Your locale is ISO 8859-1? Does it work if you start a terminal with UTF-8? Example:

```
xterm -en utf-8 -e bash -x bash -x google-translate.sh
```
Or in .bashrc, example:

```
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
export LANGUAGE=en_US.UTF-8
```
To make these changes active in the current shell: `source ~/.bashrc`.

Also I just checked, that script works ok for me in 
	
	



```
#! /bin/sh
```
You may not like the translation that Google gives, as one member pointed out, but it works.


----------



## cpm@ (Sep 3, 2013)

teckk said:
			
		

> I don't know. Your locale is ISO 8859-1? Does it work if you start a terminal with UTF-8? Example:
> 
> ```
> xterm -en utf-8 -e bash -x bash -x google-translate.sh
> ```



Thanks for your reply, but this doesn't work either.

My .cshrc locale variables:

```
setenv	LANG es_ES.UTF-8
setenv	LC_ALL es_ES.UTF-8
```

Note that I changed the shell to bash(1)(), but it still occurs the same error.

I think I missed something, so I need digging more :e

PS. In the meantime, I use this one that only needs curl(1)() and sed(1)():

```
#!/usr/local/bin/bash

USAGE="Usage: 
       $0 en es Lovely spam!
Some codes: en|fr|de|ru|nl|it|es|ja|la|pl|bo
All language codes:
http://code.google.com/apis/ajaxlanguage/documentation/reference.html#LangNameArray"

if [ "$#" == "0" ]; then
    echo "$USAGE"
    exit 1
fi

FROM_LNG=$1
TO_LNG=$2

shift 2
QUERY=$*

UA="Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.2) Gecko/20040803"
URL="http://translate.google.com/translate_a/t?client=t&hl=en&sl=$FROM_LNG&tl=$TO_LNG&otf=2&multires=1&ssel=0&tsel=0&sc=1"
curl  --data-urlencode "text=$QUERY" -A $UA -s -g -4 $URL | sed 's/","/\n/g' | sed 's/\]\|\[\|"//g' | sed 's/","/\n/g' | sed 's/,[0-9]*/ /g'
```

PPS. I tested the script in other PC and it fails at the same point :\


----------



## graudeejs (Sep 3, 2013)

cpu82 said:
			
		

> Thanks for your reply, but this doesn't work either.
> 
> My .cshrc locale variables:
> 
> ...



Also set your locale in your ~/.xinitrc / ~/.xsession. Check how I do it: https://github.com/graudeejs/dot.files/blob/master/dot.xinitrc#L2
https://github.com/graudeejs/dot.files/blob/master/dot.profile
https://github.com/graudeejs/dot.files/blob/master/dot.shrc


----------



## nickednamed (Sep 4, 2013)

There's probably a nice base system tool for this, and definitely a better way to script this, but I wrote a little script to get information about ports from the ports tree (dependencies, compile time options, pkg-descriptions, etc.)

I hope someone will find it useful!

I'm just beginning to learn shell scripting, so any suggestions, comments, etc, are very welcome.


```
#!/bin/sh

###########################################################################
# This script will allow user to search the ports tree and display port 
# categories, port names, port descriptions and dependency information.
###########################################################################


# set ports tree directory
pdir="/usr/ports"


# This is the help function which is called in case of wrong usage or the -h option.
help() { 
    echo "usage:
    `basename $0` [-a "string"] - print name, path, info, and dependencies for given string
    `basename $0` [-b port-name] - print build dependencies for given port
    `basename $0` [-d port-name] - print ALL dependencies for given port(s) recursively
    `basename $0` [-h] - print this help
    `basename $0` [-c category-name] - list category contents
    `basename $0` [-C] - list all categories in ports
    `basename $0` [-m port-name] - print missing dependencies for given port
    `basename $0` [-n port-name] - display pkg-descr contents for given port
    `basename $0` [-o port-name] - print compile-time options for given port
    `basename $0` [-s "string"] - search for given port
    `basename $0` [-S "string"] - search all "pkg-descr" files for given string
    `basename $0` [-r port-name] - print runtime dependencies for given port"
    } 

# This is what is run if no command line argument is given
if [ -z "$1" ]
then
    help
    exit 1
fi

# These are the main commands to be run for a given option.
while getopts "a:b:c:Cd:hm:n:o:s:S:r:" opt; do
      case "$opt" in
        a) cd $pdir && make search name=$2 ;;
        b) make -C $pdir/*/$2 build-depends-list | sed s:$pdir/:: | sort -d | column ;;
        c) ls -d $pdir/$2/*/ | sed s:$pdir/$2/:: | column ;;
        C) ls -d $pdir/*/ | sed s:$pdir/:: | column ;;
        d) make -C $pdir/*/$2 all-depends-list | sed s:$pdir/:: | sort -d | column ;;
        h) help ;; 
        m) make -C $pdir/*/$2 missing | sed s:$pdir/:: | sort -d | column ;;
        n) more $pdir/*/$2/pkg-descr ;;
        o) make -C $pdir/*/$2 showconfig ;;
        s) find $pdir/* -maxdepth 1 -iname *$2* | sed s:$pdir/:: | sort -d | column ;;
        S) for i in $pdir/*/*/pkg-descr; do grep -il "$2" $i | xargs dirname | sed s:$pdir/:: ; done ;; 
        r) make -C $pdir/*/$2 run-depends-list | sed s:$pdir/:: | sort -d | column ;;
        \?) echo "Type "`basename $0` -h" for help." >&2 ;;
      esac
done
```


----------



## vermaden (Sep 5, 2013)

nickednamed said:
			
		

> ```
> help() {
> echo "usage:
> `basename $0` [-a "string"] - print name, path, info, and dependencies for given string
> ...



I would only change that above into that below:


```
help() {
  NAME="$( basename $0 )"
  echo "usage:
    ${NAME} [-a "string"]        print name, path, info, and dependencies for given string
    ${NAME} [-b port-name]       print build dependencies for given port
    ${NAME} [-d port-name]       print ALL dependencies for given port(s) recursively
    ${NAME} [-h]                 print this help
    ${NAME} [-c category-name]   list category contents
    ${NAME} [-C]                 list all categories in ports
    ${NAME} [-m port-name]       print missing dependencies for given port
    ${NAME} [-n port-name]       display pkg-descr contents for given port
    ${NAME} [-o port-name]       print compile-time options for given port
    ${NAME} [-s "string"]        search for given port
    ${NAME} [-S "string"]        search all "pkg-descr" files for given string
    ${NAME} [-r port-name]       print runtime dependencies for given port"
}
```


----------



## nickednamed (Sep 6, 2013)

DziÄ™ki/Thanks.

Yes, that seems stupid running /usr/bin/basename twelve times instead of one. I don't know why I didn't see that earlier.


----------



## ShelLuser (Sep 7, 2013)

*Something for the Linux users*

Now, apologies up front if someone else has done this one before; I'll have to admit that I did not go over the entire thread just yet.

And so I used cut this evening, was going to try and help out another user of this forum:


```
$ fstat -f /home | cut -d ' ' -f3


(extra lines cut)
```
Not exactly what I expected. And yes, I know that in some cases the behaviour can be as intended:


```
$ ls -l ~ | cut -d ' ' -f3

6
2
2
6
1
```
Or does it?  Why can't I grab column 2 for example:


```
$ ls -l ~ | cut -d ' ' -f2
276


(extra lines cut)
```
Sometimes it works, and sometimes it doesn't. There is a good reason for it, but I'm spoiled and used to GNU/cut.

Enter ccut or Column Cut:


```
#!/bin/sh

## Column Cut; grab a specific column as can be done with GNU/cut.

if [ "$1/" == "/" ]; then
        echo "Usage:"                                   > /dev/stderr
        echo "`basename $0` <column number>"            > /dev/stderr
        echo                                            > /dev/stderr
        exit 1;
fi

if [ $1 -eq $1 ] 2> /dev/null; then
        sed -E 's/[[:space:]]+/ /g' | cut -d ' ' -f $1;
else
        echo "Error: please specify a column number."   > /dev/stderr
        echo                                            > /dev/stderr
        exit 1;
fi
```

So, getting column 2 in the above example:


```
$ ls -l ~ | /home/peter/bin/ccut 2
276
6
2
2
6
1
(extra lines cut)
```

Hope you'll enjoy.


----------



## jalla (Sep 7, 2013)

ShelLuser said:
			
		

> Now, apologies up front if someone else has done this one before; I'll have to admit that I did not go over the entire thread just yet.
> 
> And so I used cut this evening, was going to try and help out another user of this forum:
> 
> ...


You should try this

```
fstat -f /home | cut -w -f3
```


----------



## jb_fvwm2 (Sep 7, 2013)

[ By the way, a post a few posts after this one, references a method that works better, though I've not the time to include it here; it is in the other thread that I mention in the next post. ]

If one has a file containing a list of reinstalls due (one of the language port major version bumps, for example). One can use gcat thusly. I don't remember the procedure entirely (it is one of several).

```
p5-AnyData-0.11  (the file, [del]freebsd[/del] FreeBSD [FILE]cat[/FILE] does not work as well)

for i in $( ` gcat file ` ); do ( portmaster -d -B -i -g -P $i); done
```
worked for a while, and was tedious.  The following I am following it up with, and is more in line of the command I usually use. 

```
grep p5 file0806 | grep -v corru | head -40 | awk '{print $1}' | xargs -J % portmaster -d -B -P -i -g -x gcc-4.7.4.20130831 -x perl-5.14.4 % && yell || yell
```


----------



## ShelLuser (Sep 7, 2013)

jalla said:
			
		

> You should try this
> 
> ```
> fstat -f /home | cut -w -f3
> ```


Thanks for the suggestion but it seems you're using a different version of FreeBSD than I am. According to the cut(1) manualpage the -w parameter doesn't exist. Quite frankly I also don't recall this to exist on the cut as it's used in Linux.

As such I'll rely on my script instead for now


----------



## ShelLuser (Sep 7, 2013)

*Manage ZFS snapshots*

Although the zfs(8) manual page contains an example to setup a rolling snapshot scheme I'm not much of a believer because I like to keep "filesystem management tasks" to a minimum. As such I'm not much of a fan of renaming the whole lot of snapshots everyday, even though it could be perfectly safe.

I do like to maintain a series of snapshots though, and eventually came up with the script you see here. I figured I might as well share:


```
#!/bin/sh

## Snapshot.ZFS v1.0
##
## A script which will manage ZFS snapshots on the
## filesystem(s) of your choosing.

### Configuration section.

# ZFS pool to use.
POOL="zroot";

# Filesystem(s) to use.
FS="/home /usr/local /var"

# Retention; how many snapshots should be kept?
RETENTION=7

# Recursive; process a filesystem and all it's children?
RECURSE=yes;

### Script definitions <-> ** Don't change anything below this line! **

CURDAT=$(date "+%d%m%y");
PRVDAT=$(date -v-${RETENTION}d "+%d%m%y");
PROG=$(basename $0);

if [ ${RECURSE} == "yes" ]; then
        OPTS="-r";
fi

### Script starts here ###

if [ "$1/" == "/" ]; then
        echo "Error: no command specified."             > /dev/stderr;
        echo                                            > /dev/stderr;
        echo "Usage:"                                   > /dev/stderr;
        echo "${PROG} y : Manage snapshots."            > /dev/stderr;
        echo                                            > /dev/stderr;
        exit 1;
fi

if [ "$1" == "y" ]; then

        # Make & clean snapshot(s)
        for a in $FS; do
                ZFS=$(zfs list -r ${POOL} | grep -e "${a}$" | cut -d ' ' -f1);
                if [ "$ZFS/" == "/" ]; then
                        echo "${PROG}: Can't process ${a}: not a ZFS filesystem." >/dev/stderr;
                else
                        $(zfs snapshot ${OPTS} ${ZFS}@${CURDAT} > /dev/null 2>&1) || echo "${PROG}: Error creating snapshot ${ZFS}@${CURDAT}" > /dev/stderr
                        $(zfs destroy ${OPTS} ${ZFS}@${PRVDAT} > /dev/null 2>&1) || echo "${PROG}: Error destroying snapshot ${ZFS}@${PRVDAT}" > /dev/stderr
                fi
        done;
else
        echo "Error: wrong parameter used."             > /dev/stderr;
        echo                                            > /dev/stderr;
        echo "Usage:"                                   > /dev/stderr;
        echo "${PROG} y : Manage snapshots."            > /dev/stderr;
        echo                                            > /dev/stderr;
        exit 1;
fi
```
Configuring this script is pretty simple; you need to specify which ZFS pool to use (usually you only have one), then the filesystems which you want to manage, how many snapshots (days) to retain (keep in mind that my script was made with the intention of running it daily) and finally if you want recursive snapshots.

A little care should be taken, but the script does some checks itself, like determining the file system name based on the mount point. And it will also warn you if the directory you specified isn't a valid ZFS filesystem. What it doesn't do is check if the filesystem to destroy actually exists.

Alas, hope someone can find this useful.


----------



## jalla (Sep 7, 2013)

ShelLuser said:
			
		

> Thanks for the suggestion but it seems you're using a different version of FreeBSD than I am. According to the cut(1) manualpage the -w parameter doesn't exist. Quite frankly I also don't recall this to exist on the cut as it's used in Linux.
> 
> As such I'll rely on my script instead for now



You're right. I didn't know it was that recent, but you'd have to run -STABLE (8 or 9) to have that option. (and perhaps to state the obvious, -w makes cut treat any number of whitespace as delimiter).


----------



## jalla (Sep 7, 2013)

Thought I'd share a small script that does absolutely nothing 

Rather, it's a skeleton that I use as a starting point for every script I write. Beginning scripters may find some useful ideas here.


```
#!/bin/sh

# Desc: generic script skeleton

# defaults
x=""

print_usage () {
	echo "usage: $0 [-a aopt] [-htv]"
}

print_help () {
	print_usage
	echo " -a aopt
 -t     testrun - list actions but don't execute (implies '-v')
 -v     verbose
"
}

# print if verbose
pif () {
  test -z "$verbose" || echo "$*"
}

# run external cmds with "rc cmd arg ..."
# honours verbose/testrun options
# NB! special characters passed to this routine must be escaped carefully
rc () {
  test -z "$verbose" || echo "$*" 1>&2
  test -z "$testrun" || return
  eval "$@"
}

trap "exit 1" 15

while test -n "$1"
do
	case  $1 in
		-a) aopt=$2; shift;;
		-h) print_help;exit;;
		-t) testrun=1;verbose=1;;
		-v) verbose=1;;
		 *) print_usage;exit;;
	esac
	shift
done

pif Starting script $0
```


----------



## jb_fvwm2 (Sep 8, 2013)

jb_fvwm2 said:
			
		

> If one has a file containing a list of reinstalls due (one of the language port major version bumps, for example) ... one can use gcat thusly... don't remember the procedure entirely (it is one of several)...
> 
> ```
> p5-AnyData-0.11  (the file, freebsd [FILE]cat[/FILE] does not work as well )
> ...



Freely ignore that post: I have a one-liner running now that is working so well, in this particular upgrade,  (f one has  /var/db/pkg  as one's package database still that I posted it in the other thread ongoing presently ("FreeBSD vs Linux: 10 points...") and to the freebsd-ports list so that someone already using pkg (which ?)  maybe can craft an equivalent CLI that works as well.


----------



## teckk (Sep 10, 2013)

*A simple internet streaming radio tuner*

A simple Internet streaming radio tuner shell script for listening to radio station streams with mplayer. It should work on any Linux or FreeBSD box with bash. Resize your terminal if you keep a big list. I've already filled the list with some examples for everyone. Remove what you want, put your own in. _It d_oesn't require X. These streams are listed openly so I don't believe they violate any TOS.


```
#! /usr/bin/env bash

# A simple script to listen to radio stations online with mplayer.
# If you wish to use a different media player like vlc, ffplay, mpv etc., modify the script.
# It will hold as many stations as you want. You'll need to resize your terminal larger
# to see all of them. Add or remove stations as you wish.

# Add or Remove Stations here, use same syntax.
# Station identifier and stream
STREAMLIST='
QUIT
BBC1| -playlist http://bbc.co.uk/radio/listen/live/r1.asx
BBC1X| -playlist http://bbc.co.uk/radio/listen/live/r1x.asx
BBC2| -playlist http://bbc.co.uk/radio/listen/live/r2.asx
BBC3| -playlist http://bbc.co.uk/radio/listen/live/r3.asx
BBC4| -playlist http://bbc.co.uk/radio/listen/live/r4.asx
BBC4X| -playlist http://bbc.co.uk/radio/listen/live/r4x.asx
BBC5| -playlist http://www.bbc.co.uk/radio/listen/live/r5lsp_aaclca.pls
BBC6| -playlist http://bbc.co.uk/radio/listen/live/r6.asx
BBC_Asia| -playlist http://bbc.co.uk/radio/listen/live/ran.asx
BBC_World| -playlist http://www.bbc.co.uk/worldservice/meta/tx/nb/live/eneuk.asx
London_Heart| -playlist http://media-ice.musicradio.com/HeartLondonMP3.m3u
Nachrichten| http://ondemand-mp3.dradio.de/file/dradio/nachrichten/nachrichten.mp3
Nl_R1| -playlist http://icecast.omroep.nl/radio1-sb-mp3.m3u
Nl_R2| -playlist http://icecast.omroep.nl/radio2-sb-mp3.m3u
Nl_R5| -playlist http://icecast.omroep.nl/radio5-sb-mp3.m3u
Dk_P1| -playlist http://live-icy.gss.dr.dk:8000/A/A03L.mp3.m3u
Dk_P3| -playlist http://live-icy.gss.dr.dk:8000/A/A05L.mp3.m3u
Dk_P5| -playlist http://live-icy.gss.dr.dk:8000/A/A25L.mp3.m3u
Fr_Info| -playlist http://www.listenlive.eu/franceinfo.m3u
Fr_Chante| -playlist http://stream1.chantefrance.com/Chante_France.m3u
Fr_Radio6| -playlist http://91.121.112.215:82/xstream.m3u
De_Bayern| -playlist http://www.antenne.de/webradio/channels/info.m3u
De_Wissen| -playlist http://www.dradio.de/streaming/dradiowissen_lq_mp3.m3u
De_NDR| -playlist http://www.ndr.de/resources/metadaten/audio/m3u/ndr903.m3u
It_RAI| -playlist http://212.162.68.230/1.mp3.m3u
It_24| -playlist http://shoutcast.radio24.it:8000/listen.pls
It_Gal| -playlist http://85.47.51.98:8000/live.m3u
Esp_Nat| -playlist http://radio1.rtve.stream.flumotion.com/rtve/radio1.mp3.m3u
Esp_3| -playlist http://radio3.rtve.stream.flumotion.com/rtve/radio3.mp3.m3u
Ru_Mayak| http://live.rfn.ru/radiomayak_fm
Ru_Cty| -playlist http://79.143.70.114:8000/cityfm-64k.aac.m3u
VietNam_Pub| -playlist http://yp.shoutcast.com/sbin/tunein-station.pls?id=1548734
Jp_A| -playlist http://yp.shoutcast.com/sbin/tunein-station.pls?id=9495227
Jakarta| -playlist http://yp.shoutcast.com/sbin/tunein-station.pls?id=110954
Persian| -playlist http://yp.shoutcast.com/sbin/tunein-station.pls?id=616871
Israla| -playlist http://yp.shoutcast.com/sbin/tunein-station.pls?id=192075
InfoWars| -playlist http://www.infowars.com/infowars.asx
NPR| mms://a1671.l2063252432.c20632.g.lm.akamaistream.net/D/1671/20632/v0001/reflector:52432?
KMOX_St_Louis| http://208.80.54.57/KMOXAMAAC?
WLS_Chicago| -playlist http://provisioning.streamtheworld.com/pls/WLSAMAAC.pls
KLIF_Dallas| -playlist http://provisioning.streamtheworld.com/pls/KLIFAMAAC.pls
KFAR_Fairbanks| -playlist http://out2.cmn.icy.abacast.com/kfaram-kfaramaac-64.m3u
KGUM_Guam| -playlist http://ice2.securenetsystems.net/KGUM2.m3u
WKAQ_Puerto_Rico| -playlist http://provisioning.streamtheworld.com/pls/WKAQAMAAC.pls
KOKC_Ok_city| -playlist http://out2.cmn.icy.abacast.com/kokc-kokcamaac-64.m3u
KMBZ_Kansas_City| -playlist http://provisioning.streamtheworld.com/pls/KMBZAMAAC.pls
WOWO_Ft_Wayne| -playlist http://asx.abacast.com/federatedmedia-wowoam-32.pls
WIND_Chicago| -playlist http://provisioning.streamtheworld.com/pls/WINDAMAAC.pl 
KWQW_Des_Moines| -playlist http://provisioning.streamtheworld.com/pls/KWQWFMAAC.pls
WGN_Chicago| http://5483.live.streamtheworld.com:80/WGNAM_SC
WMBD_Peoria| -playlist http://wmbd.serverroom.us:7048/listen.pls
WSOY_Decatur| -playlist http://in.icy2.abacast.com/neuhoff-wsoyam-32.m3u
WJBC_Bloomington| -playlist http://provisioning.streamtheworld.com/pls/WJBCAMAAC.pls
KCRW_Santa_Monica| -playlist http://media.kcrw.com/live/kcrwlive.pls
FTR| http://rs4.radiostreamer.com:9110/
OTR| -playlist http://www.otrfan.com:8000/stream.m3u
WLUJ_Springfield| http://wluj.streamon.fm/stream/WLUJ-24k.aac
KJSL-St_Louis| -playlist http://den-a.plr.liquidcompass.net/pls/KJSLAMAAC.pls
VOA| -playlist http://mfile.akamai.com/2110/live/reflector:56822.asx
Bluegrass| http://173.244.215.163:8490
NRK| -playlist http://lyd.nrk.no/nrk_radio_folkemusikk_mp3_l.m3u
Copenhagen| -playlist http://onair.100fmlive.dk/klassisk_live.mp3.m3u
Sophia| -playlist http://live.btvradio.bg/classic-fm.mp3.m3u
Helsinki| -playlist http://klasu.iradio.fi:8000/klasu-med.mp3.m3u
Stockholm| -playlist http://sverigesradio.se/topsy/direkt/2562-hi-mp3.pls
Swiss_Folk| http://50.7.234.130:8188	
BR_Klassic| -playlist http://streams.br-online.de/br-klassik_1.m3u
Bayern_Folk| -playlist http://streams.br-online.de/bayernplus_1.m3u
Hamburg| -playlist http://edge.live.mp3.mdn.newmedia.nacamar.net/klassikradio128/livestream.mp3.m3u
Berlin| -playlist http://www.kulturradio.de/live.m3u	
Warsaw| -playlist http://zetclassic-02.eurozet.pl:8100/listen.pls
Krakow| -playlist http://www.miastomuzyki.pl/n/rmfclassic.pls
Polska| http://91.121.89.153:4000
Bucharest| -playlist http://stream2.srr.ro:8020/listen.pls
Bratislava| -playlist http://live.slovakradio.sk:8000/Klasika_128.mp3.m3u
Czech| -playlist http://www.play.cz/radio/cro3-128.mp3.m3u
Irish_Fav| http://173.213.97.110:8242
Irish_Folk| http://95.211.76.204:8000
Zelengrad| http://108.166.161.206:8750
Portugal| http://188.138.16.143:8290
Peru_Folk| http://108.163.250.180:8020
Bolivianisima| http://67.212.179.132:9900
Paros_FM| http://85.17.121.103:8098
'
# Don't delete the ' above this line.

clear
echo "Select a stream to start, Press q to stop stream"
select STREAM in `echo "$STREAMLIST" | cut -d "|" -f1`; do
if [[ "$STREAM" == "QUIT" ]]; then 
clear
exit
fi
GETURL=`echo "$STREAMLIST" | grep -w -m1 "^$STREAM" | cut -d "|" -f2`
if [[ -n "$GETURL" ]]; then
eval mplayer "$GETURL" &> /dev/null
fi
echo "Select another stream, Press Enter to see List, or 1 to Quit".
done
```

Get station streams here. Or wherever you wish.

http://www.thestreamcenter.com/pagestate.asp
http://www.listenlive.eu/index.html
http://www.shoutcast.com/radio/Asian
http://www.shoutcast.com/radio/Middle Eastern


----------



## listentoreason (Oct 27, 2013)

*Perl: Reformat bonnie++ results for BB Code*

I've been doing a lot of `bonnie++` benchmark runs. It is a very handy program, but I find the output (both the human-readable text and the CSV line) busy and somewhat difficult to read. I've also been running replicates to get a sense of variation in the performance, and wanted to automate processing of averages and standard deviation. I've written a Perl script that extracts Read, Write and Rewrite IO data from one or more bonnie runs and summarizes them in a compact manner. The default output is BB Code, but it will also generate TSV, CSV and TiddlyWiki markup (in case anyone else uses TW).

For example, these data:

```
1.96,1.96,RAID-Z3x8,1,1382826096,100G,,,,335851,75,243206,64,,,719959,83,124.7,11,1,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,,307ms,1686ms,,198ms,784ms,88us,130us,133us,116us,41us,236us
1.96,1.96,RAID-Z3x8,1,1382826905,100G,,,,334785,75,243253,64,,,729968,84,133.8,5,1,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,,777ms,2188ms,,167ms,813ms,87us,127us,136us,76us,41us,69us
1.96,1.96,RAID-Z3x8,1,1382827808,100G,,,,334219,75,247885,65,,,723738,83,126.9,5,1,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,,810ms,1462ms,,267ms,871ms,103us,129us,134us,75us,41us,67us
1.96,1.96,RAID-Z3x8,1,1382833099,100G,,,,337043,75,232984,61,,,721114,83,128.2,4,1,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,,300ms,2660ms,,273ms,981ms,102us,131us,149us,82us,41us,91490us
1.96,1.96,RAID-Z3x8,1,1382834158,100G,,,,330744,74,209210,54,,,510749,57,125.7,12,1,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,,1473ms,2512ms,,470ms,784ms,85us,128us,139us,88us,41us,68us
1.96,1.96,RAID-Z3x8,1,1382830980,100G,,,,332169,75,217242,57,,,711728,81,125.1,11,1,,,,,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,+++++,+++,,1029ms,1994ms,,183ms,1281ms,83us,133us,138us,78us,41us,68us
```
... if stored in a file bonnie.txt and processed with `./formatBonnie.pl bonnie.txt` will generate:

`bonnie++` [size=-2]v1.96[/size] *RAID-Z3x8* _100G N=6_
 Read=*670*[size=-2]Â±77[/size] Write=*330* Rewrite=*230*[size=-2]Â±14[/size] [size=-2](MB/sec)[/size] Latency: 260,780,2100 [size=-2](ms)[/size]

_(Using a PHP block for markup since Perl formatting does not seem to be supported in the forum)_

```
#!/usr/bin/perl -w

# Copyright Charles Tilford, 2013
# May be freely used or modified under the Perl Artistic License 2.0

# Code to help simplify bonnie++ benchmark output, including BB formatting

use strict;

my %params;
my $colMap = {
    Version        => 0,
    Machine        => 2,
    Concurrency    => 3,
    FileSize       => 5,
    Write          => 9,
    WriteCPU       => 10,
    Rewrite        => 11,
    RewriteCPU     => 12,
    Read           => 15,
    ReadCPU        => 16,
    WriteLatency   => 37,
    RewriteLatency => 38,
    ReadLatency    => 40,
};
my $mTok = {
   Read    => 'R',
   Write   => 'W',
   Rewrite => 'RW',
};
my $mCol = {
   Read    => 'green',
   Write   => 'blue',
   Rewrite => 'purple',
};
my $twBgCol = {
   Read    => '#9f9',
   Write   => '#f9f',
   Rewrite => '#ff9',
};
my $timeMap = {
    'ns' => 0.000001,
    'us' => 0.001,
    'ms' => 1,
    's'  => 1000,
};

my $results;
my $debug     = "";
my $precision = 2;
my $pm        = 'Â±';
my $sdCmpFmt  = "[/b] [size=-2]$pm%s[/size][b]";
my $sdFmt     = "[size=-2]$pm%s[/size]";
my $l10       = log(10);
my @common    = qw(Version Machine Concurrency FileSize);
my %metricH   = %{$colMap}; map { delete $metricH{$_} } @common;
my @metrics   = sort keys %metricH;
my @main      = qw(Read Write Rewrite);
my %isTime    = map { $_ .'Latency' => 1 } @main;
my %isRate    = map { $_  => 1 } @main;

my $twFmt     = '| !%s| %s | %s |';
for my $z (1..3) { map { $twFmt .= sprintf("backgroundColor:%s; %%s |",
                                           $twBgCol->{$_}) } @main }
$twFmt .= "\n";

&parse();

unless ($results) {
    warn <<HELP;

This script is designed to reformat the output from the disk
benchmarking utility Bonnie++. It can be provided with human-readable
output, or the compact comma-separated line. It will read directly
from the command line, or from one or more files. Multiple files or
bonnie strings can be passed.

Several formats are supported, including:

 BB  (Default) Use forum BB code
 TW  TiddlyWiki tabular format
 TSV Tab-separated values
 CSV Comma-separated values

To change the format, just include one of those codes on the command line:

  formatBonnie.pl bonnieOut1.txt bonnieOut2.txt TSV

HELP

exit;
}

&format();

warn "\n$debug\n" if ($debug);

sub format {
    if ($params{TW}) {
        print "| !Machine| !Mem | !N | ".join(' | ', map { "!$_" } @main).
            " |>|>| !${pm}%~StdDev |>|>| !Latency (ms) |\n";
    }
    foreach my $machine (sort keys %{$results}) {
        my $data = $results->{$machine};
        my @reps = @{$data->{raw}};
        $data->{N} = $#reps + 1;
        # Common metrics, like machine name and version:
        map { $data->{$_} = $data->{raw}[0]{$_} } @common;

        foreach my $key (@metrics) {
            # Map over average and StdDev for metrics
            my @vals = map { $_->{$key}  } @reps;
            $data->{$key} = [ &avg_stdv( \@vals ) ];
        }
        if ($params{TW}) {
            &format_tiddlywiki( $data );
        } elsif ($params{TSV}) {
            &format_tsv( $data );
        } elsif ($params{CSV}) {
            &format_csv( $data );
        } else {
            &format_bb( $data );
        }
    }
}

sub format_bb {
    my $data = shift;
    my $txt = "";
    $txt .= sprintf("[url=\"http://www.freshports.org/benchmarks/bonnie++\"][cmd]bonnie++[/cmd][/url] [size=-2]v%s[/size] [b]%s[/b] [i]%s", $data->{Version},
                    $data->{Machine}, $data->{FileSize});

    $txt .= sprintf(" N=%d", $data->{N}) if ($data->{N} > 1);
    $txt .= "[/i]\n";
    my (@lats);
    foreach my $key (qw(Read Write Rewrite)) {
        my ($avg, $sd) = map { int(0.5 + $_) } @{$data->{$key}};
        $txt .= sprintf(" %s=[color=green][b]%s[/b]", $key, $avg);
        $txt .= sprintf($sdFmt, $sd) if ($sd);
        $txt .= "[/color]";
        my ($lavg, $lsd) = @{$data->{$key.'Latency'}};
        push @lats, $lavg;
    }
    $txt .= " [size=-2](MB/sec)[/size] Latency: ".join(',', @lats)." [size=-2](ms)[/size]\n";
    print $txt;
}

sub format_bb_compact {

    # Not exposed - it was fairly garish

    my $data = shift;
    my $txt = "";
    $txt .= sprintf("Bonnie++ %s [b]%s[/b] [i]%s[/i]", $data->{Version},
                    $data->{Machine}, $data->{FileSize});

    $txt .= sprintf(" N=%d", $data->{N}) if ($data->{N} > 1);
    $txt .= "\n";
    my (@mkys, @mets, @lats);
    foreach my $key (qw(Read Write Rewrite)) {
        my ($avg, $sd) = map { int(0.5 + $_) } @{$data->{$key}};
        my $fmt = sprintf("[color=%s]%%s[/color]", $mCol->{$key});
        push @mkys, sprintf($fmt, $mTok->{$key});
        my $met = $avg;
        $met .= sprintf($sdCmpFmt, $sd) if ($sd);
        push @mets, sprintf($fmt, $met);
        my ($lavg, $lsd) = @{$data->{$key.'Latency'}};
    }
    $txt .= "[b]IO MB/sec ".join('/', @mkys).": ".join(' / ', @mets)."[/b]";
    $txt .= "\n";
    print $txt;
}

sub row {
    # Convert the data structure back into a (simplified) row
    my $data = shift;
    my @row =  ($data->{Machine}, $data->{FileSize}, $data->{N});
    push @row, map { $data->{$_}[0] } @main;
    push @row, map { $data->{$_}[2] } @main;
    push @row, map { $data->{$_.'Latency'}[0] } @main;
    return wantarray ? @row : \@row;
}

sub format_tiddlywiki {
    # [url]http://tiddlywiki.com/[/url]
    my $row  = &row( shift );
    # Bold the main metrics:
    map { $row->[$_] = "''".$row->[$_]. "''" } (3..5);
    printf($twFmt, map { $_ || "" } @{$row});
}

sub format_tsv {
    my $row = &row( shift );
    print join("\t", @{$row}) ."\n";
}

sub format_csv {
    my $row = &row( shift );
    print join(",", @{$row}) ."\n";
}

sub sigfig {
    # Round a value to specified precision
    my ($val, $sf) = @_;
    $sf ||= $precision;
    my $rv = $val;
    if ($val > 0) {
        my $exp = log($val) / $l10;
        my $mod = 10 ** (int($exp) - $sf +  ($exp > 0 ? 1 : 0));
        $rv = int(0.5 + $val / $mod) * $mod;
    }
    return $rv;
}

sub parse {
    foreach my $req (@ARGV) {
        if ($req =~ /^(bb|tw|csv|tsv)$/i) {
            # This is a configuration parameter
            $params{uc($1)} = 1;
        } elsif ($req =~ /[\+\,]{6,}/) {
            # Will assume that a stetch of '+' and ',' are a Bonnie++ line
            &parse_line( $req );
        } elsif (-s $req) {
            # A file, presume it contains Bonnie++ results
            &parse_file( $req );
        } else {
            &msg("Unrecognized parameter", $req);
        }
    }
}

sub parse_file {
    my $file = shift;
    if (open(FILE, "<$file")) {
        while (<FILE>) {
            if (/[\+\,]{6,}/) {
                &parse_line($_);
            }
        }
        close FILE;
    } else  {
        &msg("Failed to read file", $file, $!);
    }
}

sub parse_line {
    my $line = shift || "";
    $line    =~ s/[\n\r]+$//;
    my @row  = split(/\s*\,\s*/, $line);
    my %data;
    while (my ($key, $col) = each %{$colMap}) {
        my $val = $row[$col];
        if ($isTime{$key}) {
            # Normalize time to miliseconds
            if ($val =~ /(\d+)([a-z]+)/) {
                $val  = $1;
                my $u = lc($2);
                if (my $fact = $timeMap->{$u}) {
                    $val *= $fact;
                } else {
                    &msg("Unrecognized time unit '$u'");
                }
            }
        } elsif ($isRate{$key}) {
            # Normalize to MB/sec
            $val /= 1024;
        }
        $data{$key} = $val;
    }
    unless ($data{Read}) {
        &msg("Failed to parse Bonnie++ line", $line);
        return;
    }
    my $machine = $data{Machine} || "Computer";
    $results ||= {};
    push @{$results->{$machine}{raw}}, \%data;
}

sub msg {
    warn join("\n  ", map { defined $_ ? $_ : '' } @_)."\n";
}

sub avg_stdv {
    my $arr = shift;
    my $n   = $#{$arr} + 1;
    my ($sum, $sum2) = (0,0);
    foreach my $val (@{$arr}) {
        $sum  += $val;
        $sum2 += $val * $val;
    }
    my $avg = $sum / $n;
    my $std = 0;
    my $percSD = 0;
    if ($n > 2) {
        $std = sqrt(($sum2 / $n) - ($avg * $avg));
        $percSD = &sigfig(100 * $std / $avg);
    }
    $avg = &sigfig($avg);
    $std = &sigfig($std);
    if ($percSD < 1) {
        # Do not bother reporting StdDev less than 1% of average
        $percSD = $std = 0;
    }
    return ($avg, $std, $percSD);
}
```


----------



## Khaine (Nov 17, 2013)

File Integrity Checking with mtree. I found this wonderful script here and have modified it slightly*.*

```
#!/usr/local/bin/perl -w

# Globals ---------------------------------------------------------------------

# Sane default location of the mtree executable.
# Can be changed with the --mtree option.
my $mtree="/usr/sbin/mtree";
# Sane default location of the mtree file checksum database.
# Can be changed with the --checksum-file option.
my $checksum_file="/usr/mtree/fs.mtree";
# Sane default location of the mtree file exclude list.
# Can be changed with the --exclude-file option.
my $exclude_file="/usr/mtree/fs.exclude";
# Stores the executable name, mainly to refer to ourselves in help.
my $executable=$0;
# Stores the list of filesystem changes reported by mtree.
my $changes="";
# Stores the list of e-mail addresses to send results to.
my @emails;
# Whether or not to scan for file changes. 
# (default behavior, disabled in case of -uo)
my $scan_for_changes=1;
# Whether or not to update the checksums. (requires -u flag)
my $update=undef;
# Top level directory to monitor for changes. 
# (can be edited with the -p option.)
my $path="/";
# Whether or not to print scan results to stdout. 
# (Default behavior, see -q option to disable.)
my $print_results=1;
# Path to the sendmail executable.
# (see --sendmail option to change.)
my $sendmail="/usr/sbin/sendmail";
# Logfile location.
# (see -l option to change.)
my $log="/var/log/mtree.log";
# e-mail reply-to address. (see --reply-to option)
my $reply_to=undef;
# e-mail subject (see --subject option).
my $subject="Filesystem changes for " . `date`;

# Display script usage & help. ------------------------------------------------

sub show_help
{
  print '
  Usage: ' . $executable . ' [OPTION] ...
  Show or E-mail out a list of changes to the file system.

  mtree operation options:

    -u,  --update        Updates the file checksum database after 
                         showing/mailing changes.
    -uo, --update-only   Only update the file checksum database.
    -p,  --path          Top level folder to monitor (default: /)
    -q,  --quiet         Do not output scan results to stdout or any
                         other output.

  Path configuration options:

    -l,  --log           Logfile location 
                         (default: /var/log/mtree.log)
         --mtree         Set the location of the mtree executable. 
                         (default is /usr/sbin/mtree)
         --checksum-file Set the location of the file containing the 
                         mtree file checksums. 
                         (defaul: /usr/mtree/fs.mtree)
         --exclude-file  Set the location of the file containing the 
                         list of files and folders to exclude from the 
                         mtree scan. (default is /usr/mtree/fs.exclude)

  E-mail options:

    -e,  --email         Adds specified e-mail address as destination.
         --sendmail      Set the location of the sendmail executable. 
                         (default: /usr/sbin/sendmail)
         --reply-to      Set the e-mail reply-to address.
         --subject       Sets The e-mail subject. 

  Misc options:

    -h,  --help          Display this help text.
 

  Example usage:

    ' . $executable . ' -uo
    ' . $executable . ' -u -q -e foo@example.com -e bar@example.com
    ' . $executable . ' /var/www --mtree /usr/local/sbin/mtree

';

}

# Parses a command line argument and it's param. ------------------------------ 

sub parse_commandline_argument
{
  my $arg = shift;
  my $param = shift;
  if (substr($arg,0,1) eq '-')
  {
    if ($arg eq '--mtree')
    {
      $mtree = $param;
    }
    if ($arg eq '--sendmail')
    {
      $sendmail = $param;
    }
    if ($arg eq '-q' or $arg eq '--quiet')
    {
      $print_results = undef;
    }
    if ($arg eq '--reply-to')
    {
      $reply_to = $param;
    }
    if ($arg eq '--subject')
    {
      $subject = $param;
    }
    if ($arg eq '--checksum-file')
    {
      $checksum_file = $param;
    }
    if ($arg eq '-l' or $arg eq '--log')
    {
      $log = $param;
    }
    if ($arg eq '--exclude-file')
    {
      $exclude_file = $param;
    }
    if ($arg eq '-h' or $arg eq '--help')
    {
      show_help();
      exit 0;
    }
    if ($arg eq '-e' or $arg eq '--email')
    {
      if ($param =~ m/\@/)
      {
        push(@emails,$param);
      }
      else
      {
        die "Invalid e-mail address: $param\n";
      }
    }

    if ($arg eq '-u' or $arg eq '--update')
    {
      $update=1;
    }
    if ($arg eq '-uo' or $arg eq '--update-only')
    {
      $update=1;
      $scan_for_changes=undef;
    }
  }
}

# Script entry point. ---------------------------------------------------------

# Parse commandline arguments.
my $argc=0;
foreach my $argument(@ARGV)
{
  chomp($argument);
  if ($argc != $#ARGV)
  {
    my $next_argument = $ARGV[$argc+1];
    chomp($next_argument);
    parse_commandline_argument($argument,$next_argument);    
  }
  else
  {
    parse_commandline_argument($argument);
  }
  $argc++;
}

# Check if we have all the necesary components.

(-x $mtree) or die "$mtree is not executable.\n";
(-w $checksum_file) or die "$checksum_file is not writeable.\n";
(-r $exclude_file) or die "$exclude_file is not readable.\n";
if ($scan_for_changes)
{
  (-w $log) or die "$log is not writeable.\n";
}
if ($#emails >= 1)
{
  (-x $sendmail) or die "$sendmail is not executable.\n";
}

if ($print_results)
{
  print "\nScanning for changes...\n";
}

# Get the list of changed files if desired.
if ($scan_for_changes)
{
  
  $changes=`$mtree -K md5digest,sha1digest,sha256digest,ripemd160digest,cksum -f $checksum_file -X $exclude_file -p $path`;  

  # If there are no changes since last scan, then 
  # we're done with everything.
  # <= 3 to account for \n\r and maybe a space...
  if (length($changes) <= 3 )
  {
    if ($print_results)
    {
      print "All done.\n";
    }    
    exit 0;
  }

  # Write changes to log file.
  open LOGFILE,">>$log" or die $!;
  print LOGFILE $changes;
  close LOGFILE;

  # Output changes if desired.
  if ($print_results)
  {
    print "$changes\n";
  }

  # E-mail out changes if desired.
  foreach my $mail(@emails)
  {
    if ($print_results)
    {
      print "E-mailing $mail ...\n";
    }
    chomp($mail);
    open(SENDMAIL, "|$sendmail -t") or die "Cannot open $sendmail: $!";
    print SENDMAIL "To: $mail\n"; 
    if ($reply_to)
    {
      chomp($reply_to);
      print SENDMAIL "Reply-to: $reply_to\n";      
    }
    if ($subject)
    {
      chomp($subject);
      print SENDMAIL "Subject: $subject\n";      
    }
    print SENDMAIL "Content-type: text/plain\n\n";
    print SENDMAIL $changes;
    close(SENDMAIL);
  }

}

# Update checksum file if desired.
if ($update)
{
  if ($print_results)
  {
    print "Updateing checksums...\n";
  }
  system("$mtree -K md5digest,sha1digest,sha256digest,ripemd160digest,cksum -c -X $exclude_file -p $path > $checksum_file");
}

if ($print_results)
{
  print "All done.\n";
}
 

# done.
exit 0;
```

The original script used the defaults within mtree, which means only the following information is stored for each file/directory:

flags - The file flags as a symbolic name.
gid - The file group as a numeric value.
mode - The current file's permissions as a numeric (octal) or symbolic value.
nlink - The number of hard links the file is expected to have.
size - The size, in bytes, of the file.
link - The file the symbolic link is expected to reference.
time - The last modification time of the file.
uid - The file owner as a numeric value.
I modified the script to also store the following:

cksum - The checksum of the file using the default algorithm specified by the cksum(1) utility.
md5digest  - The MD5 message digest of the file.
sha1digest - The FIPS 160-1 (``SHA-1'') message digest of the file.
sha256digest - The FIPS 180-2 (``SHA-256'') message digest of the file.
ripemd160digest - The RIPEMD160 message digest of the file.
By default the script expects to be in /usr/mtree and you need to fund the following from the same directory that the script is in or the script will complain.

```
touch fs.mtree fs.exclude
touch /var/log/mtree.log
```
We can then exclude directories from the integrity checking by adding them to fs.exclude. The original script author recommended that at a minimum the following be excluded:

```
./dev
./proc
./var
./tmp
./usr/mtree
./usr/share/man
./usr/share/openssl/man
./usr/local/man
./usr/local/lib/perl5/5.8.8/man
./usr/local/lib/perl5/5.8.8/perl/man
```
Note that you have to prefix folders with ./

I run this script every hour via cron with the following, and will get an email alert if anything has changed*.*

```
@hourly root /usr/mtree/automtree -u -q -e youremail@example.com &> /dev/null
```
This script is not fool-proof. It is vulnerable to the following:

An attacker can modify the script to not call mtree*.*
An attacker can stop the script from running by modifying /etc/crontab*.*
An attacker can add all directories to fs.exclude and run the script to update only, then future changes will not be detected*.*
An attacker could modify the hashes and other attributes stored in fs.mtree*.*

I have set the script and fs.exclude to be immutable, which should protect against attack 1 and 3. You could also set your /etc/crontab to be immutable to protect against 2, but this script can not prevent attack 4 which is why I run it frequently.

To run the script you simply execute `/usr/mtree/automtree -u`.

This will updates the file checksum database after showing/mailing changes. If you have just edited a file and you want to update the file checksum database so that you won't get an alert you can run `/usr/mtree/automtree -uo`. This will only update the file checksum database.

I hope you enjoy this script and a big thanks to John Sennesael for originally creating the script.


----------



## graudeejs (Nov 17, 2013)

@Khaine, why not simply use a tool that is written for exactly this purpose such as security/tripwire, security/integrit or security/aide? 

Any of them will work much faster.


----------



## Khaine (Nov 17, 2013)

That*'*s a good question.  

I found this script online, and it suited my needs. It was simple to configure, and offers a sufficient level of security for the home server I manage. I have not had sufficient time to invest in learning how to configure one of the more robust file integrity tools.

My understanding was that security/aide in single host mode and security/integrit did not do any validation of the file hash database and so are vulnerable to the same attacks I described above.

security/tripwire and security/samhain do sign the configuration and file integrity database. I've tried using samhain in the past, but I found it a real pain to correctly configure. I have not tried security/tripwire.


----------



## nickednamed (Nov 24, 2013)

I've written myself a short script to allow normal users to mount USB devices. It was cobbled together from two or more tutorials, none of which worked for me by themselves. Therefore, it might contain some superfluous steps. It is supposed to be run as a normal user with root privileges. Feedback is welcome.


```
#!/bin/sh

# script must be run as root
if [ "$(id -u)" != "0" ]; then
   echo "This script must be run as root" 1>&2
   exit 1
fi

# making mount point "media" in user home directory...
if [ ! -d "$HOME/media" ]
	echo "creating directory $HOME/media..."
	mkdir $HOME/media
else 
	echo "the directory $USER/media already exists - continuing as normal"
fi

# giving user permission to read / write mount point
chown $USER:$USER $HOME/media

# giving normal users permission to mount devices
sysctl vfs.usermount=1

# making changes permanent in /etc/sysctl.conf
echo 'vfs.usermount=1' >> /etc/sysctl.conf

# change permissions and ownership for usb devices plugged in after boot
# making all da* devices readable and writable by their owner and wheel group
echo '[userrules=5]' >> /etc/devfs.rules
echo "add path 'da[0-9]*' mode 0660 group wheel" >> /etc/devfs.rules

# restarting devfs
/etc/init.d/devfs restart

# tell rc.conf to load the rule set every time when the system is booted
echo 'devfs_system_ruleset="userrules"' >> /etc/rc.conf

# AFAIK, the previous action doesn't affect devices available at boot

# lets change ownership and permissions of usb devices available at boot
# allow member of operator group to mount usb devices
echo 'own       /dev/da0       root:operator' >> /etc/devfs.conf
echo 'perm      /dev/da0      0660' >> /etc/devfs.conf
 

# need to add user to operator group in order to mount usb devices
# NB - as a "bonus" this will allow normal users to shutdown/reboot system
pw groupmod operator -m $USER

echo 'make sure your user is in the operator group - check the following output'
id $USER
```


----------



## vermaden (Nov 24, 2013)

@nickednamed,

You should try sysutils/automount which autodetects the filesystem on removable media and then automounts (and autounmounts) it.


----------



## nickednamed (Dec 6, 2013)

*Re:*



			
				vermaden said:
			
		

> @nickednamed,
> 
> You should try sysutils/automount which autodetects the filesystem on removable media and then automounts (and autounmounts) it.



Thanks. I'll give it a go. I'll have a  look at the source code on GitHub too - I'm sure I will learn a lot from it.


----------



## cenu (Feb 12, 2014)

Here is one for compiling freeglut applications from C source files.

```
#!/bin/sh

cc -static -c -I/usr/local/include $@.c -o $@.o
cc $@.o -L/usr/local/lib/ -lglut -lGLU -lGL -lX11 -lXext -lm -o $@
rm $@.o
```


----------



## Oko (Feb 15, 2014)

cenu said:
			
		

> Here is one for compiling freeglut applications from C source files.
> 
> ```
> #!/bin/sh
> ...


I thought that you have been supposed to use Makefiles for that


----------



## kpedersen (May 6, 2014)

Heh,

At least use set -e to cause an immediate exit on the first error.


```
#!/bin/sh

set -e

cc -static -c -I/usr/local/include $@.c -o $@.o
cc $@.o -L/usr/local/lib/ -lglut -lGLU -lGL -lX11 -lXext -lm -o $@
rm $@.o
```

But yeah... Makefiles are generally good


----------



## DutchDaemon (May 27, 2014)

*PORTUPDATER for PKGNG*

This is what I use now, under the PKGNG framework. See if it works for you. Inspect any flags and paths before actually running it. I'm not responsible for you nuking your own installation, or installing 30,000 ports.

Note that, as before, running it as `portupdater` injects a random sleep of 0-3600 seconds. So you can put it in cron, and it will mail the output to the cron owner (usually root). If you run it on the command line, add any parameter, e.g. `portupdater yes` or `portupdater a`, and it will run immediately. This also means it will perform interactive tasks, so be prepared to go through the steps.


```
#!/bin/sh

! [ -d /usr/ports ] && echo "This works much better with an installed ports tree, run 'portsnap fetch extract' first" && exit 1
! [ -f /usr/local/sbin/pkg ] && echo "You have not installed ports-mgmt/pkg yet." && exit 1
! [ -f /usr/local/sbin/portmaster ] && echo "You have not installed ports-mgmt/portmaster yet." && exit 1

/usr/bin/touch /tmp/lastportupdate
hostname=$(hostname)
date=$(/bin/date)
day=$(/bin/date | /usr/bin/awk '{print $1,$2,$3}')
oldday=$(/bin/cat /tmp/lastportupdate)

echo "
Updating portaudit first.
"
/usr/local/sbin/pkg audit -F

echo "
Portupdater for ${hostname} started at ${date}


========== Fetching latest ports snapshot from server. ==================
"

if [ $# -lt 1 ]
then
portvar="cron"
else
portvar="fetch"
fi

/usr/sbin/portsnap ${portvar} || exit 1

echo "
========== Updating ports tree with new snapshot. =======================
"
/usr/sbin/portsnap update || exit 1
cd /usr/ports && make fetchindex || exit 1

echo "
============ Cleaning out all obsolete distfiles. =======================
"
/usr/local/sbin/portmaster -y --clean-distfiles || exit 1

if [ ${portvar} = "fetch" ]
then
echo "
Ah, you're actually here. Good.

Running some (possibly) interactive stuff.
"
/bin/sleep 5

echo "
============ Cleaning out stale ports. ==================================
"
/usr/local/sbin/portmaster -s || exit 1
echo "
============ Checking port dependencies. ================================
"
/usr/local/sbin/pkg check -dn || exit 1

echo "
============ Cleaning up /var/db/ports. =================================
"
/usr/local/sbin/portmaster --check-port-dbdir || exit 1
fi

echo "
=================== See which ports need updating. ======================
"
/usr/local/sbin/pkg version -ovL '=' || exit 1

echo "
================= Warnings from /usr/ports/UPDATING. ====================
"
weekago=$( /bin/date -v-1w +%Y%m%d )
lastpkg=$( ls -D %Y%m%d -ltr /var/db/pkg | /usr/bin/tail -n1 | /usr/bin/tr -s " " "\t" | /usr/bin/cut -f 6 )
if [ ${weekago} -lt ${lastpkg} ]
 then usedate=${weekago}
 else usedate=${lastpkg}
fi
/usr/local/sbin/pkg updating -d ${usedate}
echo "
See /usr/ports/UPDATING for further details.

========== Portupdater done. ============================================

"

echo "
======================Cleaning out old packages. ========================                                                                                                                                                                    
"    
/usr/local/sbin/pkg clean -y
```


----------



## Khaine (Aug 14, 2014)

I've created a Python script to download various _IP_ blacklists. It*'*s not quite 1.0 yet. The regex filtering does not yet work, and I have not tested the auto reloading of the rules. I've put the code up on github. I welcome any contributions.


```
import urllib2
import re
import sys, argparse
import subprocess

#blocklist information

blocklists = {
	'abuse.ch Zeus Tracker (Domain)': {
		'id': 'abusezeusdomain',
		'type': 'list',
		'checks': ['domain'],
		'url':  'https://zeustracker.abuse.ch/blocklist.php?download=baddomains',
		'regex' : '',
		'file' : 'zeus.domain',
		'table' : 'zeus_domain'
	},
	'abuse.ch Zeus Tracker (IP)': {
		'id': 'abusezeusip',
		'type': 'list',
		'checks': ['ip', 'netblock'],
		'url': 'https://zeustracker.abuse.ch/blocklist.php?download=badips',
		'regex' : '',
		'file' : 'zeus.pf',
		'table' : 'zeus'
	},
	'abuse.ch SpyEye Tracker (Domain)': {
		'id': 'abusespydomain',
		'type': 'list',
		'checks': ['domain'],
		'url':  'https://spyeyetracker.abuse.ch/blocklist.php?download=domainblocklist',
		'regex' : '',
		'file' : 'spyeye.domain',
		'table' : 'spyeye_domain'
	},
	'abuse.ch SpyEye Tracker (IP)': {
		'id': 'abusespyip',
		'type': 'list',
		'checks': ['ip', 'netblock'],
		'url':  'https://spyeyetracker.abuse.ch/blocklist.php?download=ipblocklist',
		'regex' : '',
		'file' : 'spyeye.pf',
		'table' : 'spyeye'
	},
	'abuse.ch Palevo Tracker (Domain)': {
		'id': 'abusepalevoip',
		'type': 'list',
		'checks': ['domain'],
		'url':  'https://palevotracker.abuse.ch/blocklists.php?download=domainblocklist',
		'regex' : '',
		'file' : 'palevo.domain',
		'table' : 'palevo_domain'
	},
	'abuse.ch Palevo Tracker (IP)': {
		'id': 'abusepalevoip',
		'type': 'list',
		'checks': ['ip', 'netblock'],
		'regex': '',
		'url':  'https://palevotracker.abuse.ch/blocklists.php?download=ipblocklist',
		'file': 'palevo.pf',
		'table' : 'palevo'
	},
	'malwaredomains.com IP List': {
		'id': 'malwaredomainsip',
		'type': 'list',
		'checks': ['ip', 'netblock'],
		'url': 'http://www.malwaredomainlist.com/hostslist/ip.txt',
		'regex' : '',
		'file' : 'malwaredomains.pf',
		'table' : 'malwaredomains'
	},
	'malwaredomains.com Domain List': {
		'id': 'malwaredomainsdomain',
		'type': 'list',
		'checks': ['domain'],
		'url': 'http://www.malwaredomainlist.com/hostslist/hosts.txt',
		'regex': '',
		'file' : 'malwaredomains.domain',
		'table' : 'malwaredomains_domain'
	},
	'PhishTank': {
		'id': 'phishtank',
		'type': 'list',
		'checks': ['domain'],
		'url': 'http://data.phishtank.com/data/online-valid.csv',
		'regex': '/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/',
		'file' : 'phishtank.domain',
		'table' :'phishtank_domain'

	},
	'malc0de.com List': {
		'id': 'malc0de',
		'type': 'list',
		'checks': ['ip', 'netblock'],
		'url': 'http://malc0de.com/bl/IP_Blacklist.txt',
		'regex' : '',
		'file' : 'malc0de.pf',
		'table' : 'malc0de'
	},
	'TOR Node List': {
		'id': 'tornodes',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://torstatus.blutmagie.de/ip_list_all.php/Tor_ip_list_ALL.csv',
		'regex' : '',
		'file' : 'tornodes.pf',
		'table' : 'tor_nodes'

	},
	'blocklist.de List': {
		'id': 'blocklistde',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://lists.blocklist.de/lists/all.txt',
		'regex' : '',
		'file' : 'blocklistde.pf',
		'table' : 'blocklistde'
	},
	'Autoshun.org List': {
		'id': 'autoshun',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://www.autoshun.org/files/shunlist.csv',
		'regex': '\((\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))\b\)ssss',
		'file' : 'autoshun.pf',
		'table' : 'autoshun'
	},
	'Internet Storm Center': {
		'id': 'isc',
		'type': 'query',
		'checks': [ 'ip' ],
		'url': 'https://isc.sans.edu/api/topips/records/1000/today/handler?json',
		'regex': '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b',
		'file': 'isc.pf',
		'table' : 'storm_center:'
	},
#	'AlienVault IP Reputation Database': {
#		'id': 'alienvault',
#		'type': 'list',
#		'checks': [ 'ip', 'netblock' ],
#		'url': 'https://reputation.alienvault.com/reputation.generic',
#		'regex': '',
#		'file': 'alienvault.pf',
#		'table' : 'alienvault'
#	},
	'OpenBL.org Blacklist': {
		'id': 'openbl',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://www.openbl.org/lists/base.txt',
		'regex' : '',
		'file' : 'openbl.pf',
		'table' : 'openbl'
	},
	'Nothink.org SSH Scanners': {
		'id': 'nothinkssh',
		'type': 'list',
		'checks': [ 'ip', 'netblock', 'domain' ],
		'url': 'http://www.nothink.org/blacklist/blacklist_ssh_week.txt',
		'regex' : '',
		'file' : 'nothinkssh.pf',
		'table' : 'nothinkssh'
	},
	'Nothink.org Malware IRC Traffic': {
		'id': 'nothinkirc',
		'type': 'list',
		'checks': [ 'ip', 'netblock', 'domain' ],
		'url': 'http://www.nothink.org/blacklist/blacklist_malware_irc.txt',
		'regex' : '',
		'file' : 'nothinkirc.pf',
		'table' : 'nothinkirc'
	},
	'Nothink.org Malware HTTP Traffic': {
		'id': 'nothinkhttp',
		'type': 'list',
		'checks': [ 'ip', 'netblock', 'domain' ],
		'url': 'http://www.nothink.org/blacklist/blacklist_malware_http.txt',
		'regex' : '',
		'file' : 'nothinkhttp.pf',
		'table' : 'nothinkhttp'
	},
	'C.I. Army Malicious IP List': {
		'id': 'ciarmy',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://cinsscore.com/list/ci-badguys.txt',
		'regex' : '',
		'file' : 'ciarmy.pf',
		'table' : 'ciarmy'
	},
	'Spamhaus drop list': {
		'id': 'spamhaus',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://www.spamhaus.org/drop/drop.lasso',
		'regex' : '',
		'file' : 'spamhaus.pf',
		'table' : 'spamhaus'
	},
	'Emerging Threats - Russian Business Networks List': {
		'id': 'emergingthreats-rbn',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://rules.emergingthreats.net/blockrules/rbn-ips.txt',
		'regex' : '',
		'file' : 'emergingthreats-rbn.pf',
		'table' : 'emergingthreats-rbn'
	},
	'Project Honeypot': {
		'id': 'projecthoneypot',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://www.projecthoneypot.org/list_of_ips.php?t=d&rss=1',
		'regex' : '',
		'file' : 'projecthoneypot.pf',
		'table' : 'projecthoneypot'
	},
	'Rulez.sk blocklist': {
		'id': 'rulez.sk',
		'type': 'list',
		'checks': [ 'ip', 'netblock' ],
		'url': 'http://danger.rulez.sk/projects/bruteforceblocker/blist.php',
		'regex' : '',
		'file' : 'rulez.sk.pf',
		'table' : 'rulez.sk'
	}
		
}

def downloadAndProcessBlocklist(url, regex, filename):
	req = urllib2.Request(url)
	req.add_header('User-Agent', 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)')

	#download blocklist
	try:
		response = urllib2.urlopen(req)
		contents = response.read()

	except urllib2.URLError as e:
		if hasattr(e, 'reason'):
			print 'We failed to reach a server.'
			print 'Reason: ', e.reason
		elif hasattr(e, 'code'):
			print 'The server couldn\'t fulfill the request.'
			print 'Error code: ', e.code
		else:
			print 'unknown error'

	#process blocklists
	if regex != '':
		
		match = re.findall(regex, contents)
		
		print match
		
		contents = match

	#write to file
	try:
		with open(location+filename, 'w') as f:
			f.write(contents)
			f.close()
	except IOError as e:
  		print e.reason

def reloadFirewallRules(firewall, location, table):

	if firewall == 'pf':

		print ('/sbin/pfctl l -t ' + table + ' -Tr -f ' + location+value['file'])
		#subprocess.call(['/sbin/pfctl l -t ' + table + ' -Tr -f ' + location+value['file']])

#	if firewall == 'iptables':
		#todo

# main

#sensible defaults
firewall = 'pf'
listType = 'ip'
location = '/root/tables/'

parser = argparse.ArgumentParser(description='IP blocklist downloader and importer for pf and ip tables')
parser.add_argument('-fw', '--firewall_type',help='firewall type, currently pf and iptables are supported', required=False)
parser.add_argument('-t', '--blocklist_type',help='blocklist type, currently ip, netblock, domain and all are supported', required=True)
parser.add_argument('-l', '--blocklist_location',help='location to store blocklists', required=False)
parser.add_argument('-n', '--blocklist_names',help='specify names of blocklists to download', required=False, type=lambda s: [str(item) for item in s.split(',')])

args = parser.parse_args()

if args.blocklist_type in ['ip','domain','netblock']:
	listType = args.blocklist_type
else:
	print('Invalid option, only ip, domain and netblock are currently supported')
	sys.exit(2)

if args.firewall_type != None:
	firewall = args.firewall_type

if args.blocklist_location != None:
	location = args.blocklist_location


for key, value in sorted(blocklists.items()):

	#download all blocklists of the given type
	if args.blocklist_names == None:
		if listType in value['checks']:
			print('downloading '+key)
			downloadAndProcessBlocklist(value['url'], value['regex'], value['file'])
			reloadFirewallRules(firewall, location, value['table'])
	else:
		#download specified blocklists
		if value['id'] in args.blocklist_names:
			print('downloading '+key)
			downloadAndProcessBlocklist(value['url'], value['regex'], value['file'])
			reloadFirewallRules(firewall, location, value['table'])
```


----------



## uzsolt (Sep 24, 2014)

Sometimes you'll need a temporary directory to test an idea (to help on a forum  ), build source, etc.
A simple `csh`-alias:

```
alias use-sb 'setenv SANDBOX `mktemp -d /home/zsolt/sandbox/sandbox.XXXXXXXX` ; tcsh -l ; rm -rf ${SANDBOX}'
```
and relevant part of my ~/.login:

```
if (${?SANDBOX} == 1) then
        cd ${SANDBOX}
        set prompt = "${green}%n ${white}|${cyan} %T ${white}| ${yellow}%~${end} \n${magenta}<sandbox>${blue} $ ${end} "
    endif
```

When I run `use-sb`, runs a new `tcsh`-shell, the prompt will be "sandbox-specify", `cd` into sandbox-directory. When I exit from this shell (Control-D), the sandbox directory will be erased.


----------



## Carpetsmoker (Oct 23, 2014)

grepe, short for "grep edit":

```
#!/bin/sh

vim -p `grep $* | cut -d: -f1 | sort -u | xargs`
```

I don't use grep much these days, in favour of the_silver_searcher, so I also have age:


```
#!/bin/sh

vim -p `ag $* | cut -d: -f1 | sort -u | xargs`
```

xvim creates a file, and immediately makes it executable; useful for little test scripts (saves a `^Z`, `chmod a+x`, `fg`):


```
#!/bin/sh

touch $*
chmod a+x $*
vim -p $*
```


----------



## jb_fvwm2 (Nov 17, 2014)

I've tested something like this before, but this is the first time it returned without consequence to the original window manager. One should have at least two xinitrc though, from a running xterm or simila.

```
xinit /usr/local/etc/X11/xinit/xinitrc-openbox -- /usr/local/bin/Xorg :1 -dpi 120 ttyve
```
 then to return to the original window manager, just log out of Openbox. I have too little time to test with other window managers, though.


----------



## mb2015 (Oct 20, 2015)

DutchDaemon said:


> PORTUPDATER for PKGNG


What's the reason for `make fetchindex`? Your `portsnap` fetch/update gets the index files already.


----------



## cpm@ (Oct 21, 2015)

mb2015 said:


> What's the reason for `make fetchindex`? Your `portsnap` fetch/update gets the index files already.



Please, read the following quote:


SirDice said:


> Make index will create the index by looking at your current ports tree. Make fetchindex will just fetch the index from a repository server. Fetchindex has the potential of fetching a different index compared to the ports tree that is actually on your system.



Posted in Thread 3566.


----------



## mb2015 (Oct 21, 2015)

I saw that, actually, but didn't understand why you would want to your index to possibly be newer than the rest of your ports tree. From that same thread:



fronclynne said:


> portsnap theoretically guarantees a consistent ports tree & INDEX: you're getting a snapshot of a sessile hierarchy.


----------



## kpa (Oct 21, 2015)

mb2015 said:


> I saw that, actually, but didn't understand why you would want to your index to possibly be newer than the rest of your ports tree. From that same thread:



Actually portsnap(8) is guaranteed to give you a ports tree and INDEX that are in sync. The reason for doing `make fetchindex` is when you're using SVN for fetching and updating the ports tree and you're too lazy to run `make index`. The slight discrepancy between the tree and the INDEX file usually doesn't cause any problems.


----------



## mb2015 (Oct 22, 2015)

We're talking past each other. The script is not using `svn`. It is using `portsnap fetch`, and then:

```
/usr/sbin/portsnap update || exit 1
cd /usr/ports && make fetchindex || exit 1
```
I am asking why does it do this `make fetchindex` step? It is replacing the good index with one that may be out of sync with the rest of the ports tree.


----------



## Aic (Oct 22, 2015)

I'll be glad, if this experimental notes will be useful for anyone.

device.map

```
(hd0) /usr/local/VirtualBox/vmm/vmd0
(cd0) /usr/home/openSUSE/openSUSE-13.2-DVD-x86_64.iso
```
vm0.sh

```
#!/bin/sh
#kldload vmm.ko
#kldload nmdm.ko
#truncate -s 8G /usr/local/VirtualBox/vmm/vmd0

# Installation
#grub-bhyve -m device.map -r cd0 -M 1024M suse0
#grub> linux (cd0)/boot/x86_64/loader/linux
#grub> initrd (cd0)/boot/x86_64/loader/initrd
#grub> boot

# Usage
grub-bhyve -d /boot/grub2 -m device.map -r hd0,msdos2 -M 1024M vm0
#grub> linux (hd0,msdos2)/boot/vmlinuz
#grub> initrd (hd0,msdos2)/boot/initrd
#grub> boot

bhyve \
-A -H -P -m 1024M \
-s 0:0,hostbridge \
-s 1:0,lpc \
-s 2:0,ahci-cd,/usr/home/openSUSE/openSUSE-13.2-DVD-x86_64.iso \
-s 3:0,ahci-hd,/usr/local/VirtualBox/vmm/vmd0 \
-s 4:0,virtio-net,tap0 \
-l com1,stdio \
vm0

#cu -l /dev/nmdm0B -s 9600

#bhyvectl --destroy --vm=suse0
#ifconfig tap1 destroy
#kldunload nmdm.ko
#kldunload vmm.ko
```
It is not "ready for use" script. It's fine in one sense - It works!


----------



## cpm@ (Oct 24, 2015)

mb2015 said:


> We're talking past each other. The script is not using `svn`. It is using `portsnap fetch`, and then:
> 
> ```
> /usr/sbin/portsnap update || exit 1
> ...



`make fetchindex` brings a new INDEX-10 instead use the index with portsnap(8) (pre-generated one by another person).

```
% ls -al /usr/ports/IND*
-rw-r--r--  1 root  wheel  32320527 Oct 24 17:35 /usr/ports/INDEX-10
-rw-r--r--  1 root  wheel  32780684 Oct 24 17:35 /usr/ports/INDEX-9
```


----------



## jrm@ (Apr 1, 2016)

Here's one to maintain ZFS snapshots with cron.  It's inspired by ZfSnap, but does a few things differently and has a simpler interface.  It's been working well for me, but it's new and hasn't been tested on OSes other than FreeBSD.

https://github.com/Jehops/zap


----------



## tobik@ (Apr 1, 2016)

jrm said:


> Here's one to maintain ZFS snapshots with cron.  It's inspired by ZfSnap, but does a few things differently and has a simpler interface.  It's been working well for me, but It's new and hasn't been tested on OSes other than FreeBSD.
> 
> https://github.com/Jehops/zap


I will try this one out later. A terrifying name for a snapshot tool though


----------



## jrm@ (Apr 1, 2016)

I made some updates.  If you are playing with it, please pull again.
https://github.com/Jehops/zap


----------



## jrm@ (Apr 5, 2016)

It's in the ports tree now: sysutils/zap.


----------



## nORKy (Jun 16, 2016)

Hi, I'm searching for a 'clean script' after a clone of my FreeBSD Virtual Machine. The question is not really how to write the script but what to clean? SSH host keys, some /var/log/*, ...
Thanks you


----------



## vermaden (Jul 18, 2016)

Script to generate Openbox menu with selection of the default Sound output (uses /dev/sndstat and sysctl hw.snd.default_unit=X).

Looks like that:





Script itself:

```
% cat ~/bin/__openbox_freebsd_sound.sh
#! /bin/sh

echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
echo "<openbox_pipe_menu>"

echo "<item label=\"FreeBSD Sound Devices\">"
echo "  <action name=\"Execute\">"
echo "  <command>cat /dev/sndstat</command>"
echo "  </action>"
echo "</item>"

echo "<separator />"

if [ -e /dev/sndstat ]
then
  cat /dev/sndstat \
  | sed 1d \
  | grep play \
  | while read DEVICE
  do
  NUMBER=$( echo "${DEVICE}" | awk -F':' '{print $1}' | grep -o -E "[0-9]+" | sed 's|<|&lt;|g' | sed 's|>|&gt;|g' )
  CMD="sudo sysctl hw.snd.default_unit=${NUMBER}"
  NAME=$( echo "${DEVICE}" | sed 's|<|\&lt;|g' | sed 's|>|\&gt;|g' )
  echo "<item label=\"${NAME}\">"
  echo "  <action name=\"Execute\">"
  echo "  <command>${CMD}</command>"
  echo "  </action>"
  echo "</item>"
  done

  echo "<separator />"

  CURRENT=$( cat /dev/sndstat | grep 'default$' )
  NAME=$( echo "${CURRENT}" | sed 's|<|\&lt;|g' | sed 's|>|\&gt;|g' )
  echo "<item label=\"CURRENT: ${NAME}\" />"
else
  echo "<separator label=\"The /dev/sndstat file is not available.\" />"
fi

echo "</openbox_pipe_menu>"
```


----------



## vermaden (Jul 19, 2016)

How to generate acceptance for ALL possible licenses in the FreeBSD Ports tree?


```
That way:
# grep -h -o -r '^LICENSE_NAME_.*=' /usr/ports \
  | sort -u \
  | tr -d '=' \
  | sed 's|LICENSE_NAME_||'g \
  | grep -v '${lic}' \
  | while read I
    do
      echo LICENSES_ACCEPTED+=${I}
    done
LICENSES_ACCEPTED+=3GPP
LICENSES_ACCEPTED+=ACUBE
LICENSES_ACCEPTED+=ADOBE
LICENSES_ACCEPTED+=APL1
LICENSES_ACCEPTED+=BSDCOMPATIBLE
LICENSES_ACCEPTED+=BSIML
LICENSES_ACCEPTED+=BuildLic
LICENSES_ACCEPTED+=CC0
LICENSES_ACCEPTED+=CCBYNCSAv3
LICENSES_ACCEPTED+=CCBYSAv3
LICENSES_ACCEPTED+=CCBYv3
LICENSES_ACCEPTED+=CCbyNC25
LICENSES_ACCEPTED+=CCbyNCSA2
LICENSES_ACCEPTED+=CCbyNCSA3
LICENSES_ACCEPTED+=CCbySA30
LICENSES_ACCEPTED+=CCbySA3
LICENSES_ACCEPTED+=CCbySA40
LICENSES_ACCEPTED+=CCbySA
LICENSES_ACCEPTED+=CLEARTHOUGHT
LICENSES_ACCEPTED+=COMMERCIAL
LICENSES_ACCEPTED+=CPL05
LICENSES_ACCEPTED+=CPL
LICENSES_ACCEPTED+=CUBE
LICENSES_ACCEPTED+=CW
LICENSES_ACCEPTED+=CeCILL
LICENSES_ACCEPTED+=CeCILL_C
LICENSES_ACCEPTED+=DMD
LICENSES_ACCEPTED+=DejaVu
LICENSES_ACCEPTED+=ECW
LICENSES_ACCEPTED+=EULA
LICENSES_ACCEPTED+=EUPL
LICENSES_ACCEPTED+=FAL
LICENSES_ACCEPTED+=FDK_AAC
LICENSES_ACCEPTED+=FFTPAK
LICENSES_ACCEPTED+=FLOSSE
LICENSES_ACCEPTED+=FPL
LICENSES_ACCEPTED+=GLEW
LICENSES_ACCEPTED+=GPLR
LICENSES_ACCEPTED+=HISIML
LICENSES_ACCEPTED+=HW
LICENSES_ACCEPTED+=IBM
LICENSES_ACCEPTED+=ICOT
LICENSES_ACCEPTED+=ICU
LICENSES_ACCEPTED+=IDPL
LICENSES_ACCEPTED+=IFL
LICENSES_ACCEPTED+=IPL
LICENSES_ACCEPTED+=ISO
LICENSES_ACCEPTED+=IUP
LICENSES_ACCEPTED+=JAIDL
LICENSES_ACCEPTED+=JDOM
LICENSES_ACCEPTED+=JYTHON
LICENSES_ACCEPTED+=LINUXLIBERTINE
LICENSES_ACCEPTED+=LinuxdocTools
LICENSES_ACCEPTED+=MSPAT
LICENSES_ACCEPTED+=NAIST
LICENSES_ACCEPTED+=NAISTL
LICENSES_ACCEPTED+=NEWRELIC
LICENSES_ACCEPTED+=NKF
LICENSES_ACCEPTED+=NODE
LICENSES_ACCEPTED+=OFL
LICENSES_ACCEPTED+=OPENLDAP
LICENSES_ACCEPTED+=OTHER
LICENSES_ACCEPTED+=PUBLIC_DOMAIN
LICENSES_ACCEPTED+=PerconaFT
LICENSES_ACCEPTED+=QPL10
LICENSES_ACCEPTED+=SENDMAIL
LICENSES_ACCEPTED+=SIL
LICENSES_ACCEPTED+=SpecialAuth
LICENSES_ACCEPTED+=TTYP0
LICENSES_ACCEPTED+=TWAIN
LICENSES_ACCEPTED+=TclTk
LICENSES_ACCEPTED+=UIUC
LICENSES_ACCEPTED+=UNLICENSE
LICENSES_ACCEPTED+=UNRAR
LICENSES_ACCEPTED+=VOLITION
LICENSES_ACCEPTED+=W3C
LICENSES_ACCEPTED+=WARSOW
LICENSES_ACCEPTED+=addl
LICENSES_ACCEPTED+=imlib2
LICENSES_ACCEPTED+=unknown
```

Then put all these LICENSES_ACCEPTED+=* lines into the /etc/make.conf file.


----------



## RedShift1 (Aug 15, 2016)

Basic script to dump the root filesystem to a remote host with incrementals... https://github.com/RedShift1/randomstuff/blob/master/bash-scripts/backup.sh


----------



## robroy (Aug 28, 2016)

Here's how I see jailed userland versions:

```
% cat jls-version
#!/bin/sh
for JAIL in `jls | grep -v JID | awk '{print $3}'`; do 
    echo -n "$JAIL "
    jexec $JAIL freebsd-version
done | awk '{print $2 "  " $1}' | sort
```
'looks like this:

```
# jls-version
10.0-RELEASE-p12  dhcp
10.0-RELEASE-p12  jamclod
10.0-RELEASE-p12  ns
10.1-RELEASE-p31  ns-dmz
10.1-RELEASE-p37  dhcp-dmz
10.1-RELEASE-p37  funmax
10.1-RELEASE-p37  ns-inet
10.1-RELEASE-p37  www
10.2-RELEASE-p10  alf
10.2-RELEASE-p10  samba36a
10.2-RELEASE-p10  samba42a
10.2-RELEASE-p10  samba42b
10.2-RELEASE-p10  samba43a
10.2-RELEASE-p14  squid
10.2-RELEASE-p17  milk1-r
10.2-RELEASE-p20  mail
```


----------



## zirias@ (Aug 28, 2016)

pdfetch, pre-fetching for poudriere

This is only useful on a painfully slow internet connection like mine at the moment (still waiting for DSL, using UMTS right now) -- parallel fetches often fail on me, so I now use this before running `poudriere bulk`:


```
#!/bin/sh

PORTSLIST=/etc/pdports
PORTSDIR=/usr/local/poudriere/ports/default
PORT_DBDIR=/usr/local/etc/poudriere.d/11a-options
DISTDIR=/usr/local/poudriere/distfiles
MAKE_CONF=/usr/local/etc/poudriere.d/make.conf

for PORT in `cat ${PORTSLIST}`; do
    make __MAKE_CONF=${MAKE_CONF} \
        PORTSDIR=${PORTSDIR} PORT_DBDIR=${PORT_DBDIR} \
        DISTDIR=${DISTDIR} \
        -C ${PORTSDIR}/${PORT} fetch-recursive
done
```
just set the variables accordingly to your poudriere setup and run it.


----------



## jrm@ (Jan 29, 2017)

I updated sysutils/zap to version 0.6.5.  The biggest change since I last posted is that it now supports remote replication.  This blog post is a short description of how I have been doing backups.


----------



## debguy (Jan 29, 2017)

Here's what I do it's Custom 

I don't bother with "non-living" backups.  If I have a machine fail I want to slide over to the next one and continue (my college days - get the report *finished*).  The cost of a (2nd hand) PC to house the backup disk in - minimal - the benefits - great.

I keep 2-3 machines synchronized BY HAND (rsync) and use RCS to keep EACH FILE incrementally saved.  Here's how and why.  It saves time and is more useful, and stable.

I use RCS whenever I edit a hand edited script or have hour of change to some edited file.  This means there are two copies of each file: dir/file and dir/RCS/file,v.  Loss of file?  just co -l file - no need to (telnet/rsh/ssh) live running "backup".  If somehow i delete a whole dir tree (very rare i do) ... i just rsync it from the other pc.  no backup software needed.  if i need another pc - i just copy the whole drive and boot the new pc - no restoring bacup needed.  Another thing: say software installs and clobbers file: just co -l file.  RCS is 100x more efficient than keeping incremental backups.

Caveate: only broadcast/synchronize file,RCS/file,v to all hosts (srdist file) by hand.  Only a human realizes which copy is really the newer and has just edited changes - and unix time is too easily wrong to use time as an indicator!  I tried a few schemes for automated: they have serious flaws of continually having A WRONG versioned file as newer - and that might make or break a whole backup as to if restoring it helps !!  one file.

At first it sounds like work using RCS for each edit.  But compared to using incremental backups it's a HUGE timesaver.  And it also means you can shift between two PC at all times for reasons other than backups.  Just to use 2 or  at once.

I don't backup the OS because that can be re-installed - and likely changes anywho - whether i like it, or agree, or not.  I hate incompatibility changes - often new releases are just damaged UNIX - just changed defaults and fewer features *available* due to hacking unix away from being unix.  Not to mention: nothing works and everything must be hacked to fit joe schmo's hack to the core to fix his misfit past hacks   These days - rebuilding/recompiling a complete distro fresh (assuming one has a script for doing so) takes not much longer than restoring a backup.  Then one only needs their hand edited configs - which are RCS kept and kept outside system directories.  I NEVER keep any hand-edited files in system directories, as these are systematically destroyed during re-install or upgrades or what.

I found out long ago that 1 backup isn't enough: there's a chance there's a fatal flaw with the back OR a chance you'll damage the backup (or the system being restored) when trying to restore.  Therefore I prefer 3 living copies, just like accounting, always.

Caveate: beginners would not understand why to do this or what to do if they loose a file or a system.  beginners would not understand how to keep hand-edited files clear of system directories that get clobbered.  beginners would not necessarily appreciate or be able to keep 3 different kinds of PC up running living and synchronized - though the process simple when OS install is left aside (problem?  os install is not really aside).

where to see scripts i use (here, only srdist really describes my convenient rsync wrapper 'srdist' simple file distributing):

https://sourceforge.net/projects/x-lfs-2010/
https://sourceforge.net/projects/ (see srdist)

i've been wanting to install bsd 4.3 or 10.  btw i'm new to bsd on apple.  but linux has allot in common (ie, early linux had mostly/wholey ripped bsd4.3 userland)


----------



## debguy (Jan 29, 2017)

as far as having a backup disk and restoring a whole computer from an old backup?

i've never done it even once with unix.  why is because it's never really my intent to do that.

i've only ever installed OS fresh and restored my personal files from still (incremental) backups.  i never want an os that failed and caused a re-install or even it's near image !  i frequently want something different with OS if i'm even bothering.  and for me: it's very rare to do.

restoring personal files from an whole disk backup is a process i decided was too timely to keep doing - all that damn "cd dir; ls -al" is timely.  rcs and rsync take a little extra time when "saving changes to files", but i would argue pay off.


----------



## r0g3r (May 3, 2017)

search for the port and installs, if it is already installed it reinstalls


```
#!/bin/sh

NETBSD_PORTS="/usr/pkgsrc"
FREEBSD_PORTS="/usr/ports"

if [ `uname -s` == "NetBSD" ];
  then
  if [ -e "/usr/pkg/bin/$1" ];
    then
    find $NETBSD_PORTS -name $1 -exec make reinstall clean -C {} \;
  else
    find $NETBSD_PORTS -name $1 -exec make install clean -C {} \;
  fi

elif [ `uname -s` == "FreeBSD" ];
  then
  if [ -e "/usr/local/bin/$1" ];
    then
    find $FREEBSD_PORTS -name $1 -exec make reinstall clean -C {} \;
  else
    find $FREEBSD_PORTS -name $1 -exec make install clean -C {} \;
  fi
fi
```


----------



## SirDice (May 3, 2017)

There are a few things wrong with it. It'll work for basic things like sysutils/tmux when the executable happens to have the same name as the port. But a lot of ports use names that don't reflect the executables. 

Probably a better solution would be something like this:

```
if [ -e "/usr/local/bin/$1" ]; then
    PORTNAME=`pkg which -oq /usr/local/bin/$1`
    make reinstall clean -C "${FREEBSD_PORTS}/${PORTNAME}" 
fi
```


```
# pkg which -oq /usr/local/bin/mysql
databases/mysql57-client
```
See pkg-which(8).

There's probably a cool pkg-rquery(8) to find packages for executables that aren't installed. But care must be taken, there are several different ports providing /usr/local/bin/mysql for example (think MySQL 5.5, 5.6, 5.7, MariaDB etc.). And all of them conflict with any of the others.


----------



## r0g3r (May 4, 2017)

SirDice said:


> There are a few things wrong with it. It'll work for basic things like sysutils/tmux when the executable happens to have the same name as the port. But a lot of ports use names that don't reflect the executables.
> 
> Probably a better solution would be something like this:
> 
> ...



thank you, I will implement the script


----------



## dpx (Aug 12, 2017)

Since I am new here I am still trying to wrap my head around basic package management, who installs what, from where etc. So here are two one liners that help me a lot:

List all explicitly installed packages from 'unknown-repository' (so lists all ports?), sorted by size:

```
pkg query -e '%a = 0' "%n;%v;%sh;%R;%sb" | grep -i unknown-repository | sort --field-separator=';' -g -k5 | cut -f 1,2,3,4 -d';' | column -s';' -t
```

Same but for known repositories (so lists all binary packages?):

```
pkg query -e '%a = 0' "%n;%v;%sh;%R;%sb" | grep -v unknown-repository | sort --field-separator=';' -g -k5 | cut -f 1,2,3,4 -d';' | column -s';' -t
```

Sizes are not ideal since I don't count all the dependencies but it is good enough to give a bird view of the system userland.


----------



## ronaldlees (Aug 12, 2017)

A command line I use often, to corral bunches of files into a directory:

`find . -type f -name "*.txz" -exec cp {} /usr/home/ron/collection \;`

It's old as dirt, and pretty obvious, but maybe not to some noobies.   It searches, starting at the dot dir, for all files with the "txz" extension, and puts them into the ~/collection directory.


----------



## graudeejs (Sep 26, 2017)

Some while ago I was fed up with all the linux package management tools. Every one of of them works differently. So I decided to write simple wrapper called repkg.
Here's link to repository: https://github.com/graudeejs/repkg

The idea is to have common interface that will abstract package management in a way that would be similar to pkgng.


----------



## wolffnx (Sep 28, 2017)

ronaldlees said:


> A command line I use often, to corral bunches of files into a directory:
> 
> `find . -type f -name "*.txz" -exec cp {} /usr/home/ron/collection \;`
> 
> It's old as dirt, and pretty obvious, but maybe not to some noobies.   It searches, starting at the dot dir, for all files with the "txz" extension, and puts them into the ~/collection directory.



is the swiss army knife for me, works across FreeBSD and Linux systems..classic but util


----------



## graudeejs (Oct 18, 2017)

As a web systems developer I often need to dump production database. However to be able to do that, I also need to ssh to production sever (due to firewall on DB server).
This is very cumbersome.
To make my life easier I've developed two scripts that utilize my password store.

db.sh allows me to access production db from remote host by simply typing

```
db.sh db/production
```
dump_db.sh allows me to dump production db from remote host

```
dump_db.sh db/production > dump.sql.gpg
```
To improve performance, I'm compressing dumped SQL with gzip server side, then ungzip on local PC. Instantly dump is gpg encrypted with my public key (because I'm on laptop and I don't fully trust hardware based encryption)

The password store file contains simple configuration.
Something like

```
db_password
ssh: user@example.com
host: in-the-cloud.eu-west-1.rds.amazonaws.com
adapter: mysql
username: db_username
database: db_name
port: 3306
```

P.S.
While I'm here I want to mention Nitrokey that ensures that my private keys stay safe.


----------



## shepper (Oct 19, 2017)

I have a couple of scripts that I use to retrieve U.S Weather service information.  I prefer these over Gnome/KDE/Xfce4 weather applets because they retrieve from U.S rather than the hard coded source in Northern Europe.  Also does not constantly poll a site saving cpu cycles and bandwidth.
This one retrieves Aviation weather from the nearest airport that offers weather services.  My nearest airport is in Yakima,WA (KYKM).  Alternative US airport codes are here.

```
#!/bin/sh
curl -sk http://tgftp.nws.noaa.gov/data/observations/metar/decoded/KYKM.TXT | \
fold -w 78 -s
echo ""
printf "<Enter to Close>"; read nothing
```

I've coupled it with a x11/yad entry that places a small cloud in my panels system tray and it generates this:

```
YAKIMA AIR TERMINAL, WA, United States (KYKM) 46-34N 120-32W 324M
Oct 26, 2017 - 05:53 PM EDT / 2017.10.26 2153 UTC
Wind: from the NNE (020 degrees) at 5 MPH (4 KT):0
Visibility: 10 mile(s):0
Sky conditions: clear
Temperature: 66.9 F (19.4 C)
Dew Point: 34.0 F (1.1 C)
Relative Humidity: 29%
Pressure (altimeter): 30.29 in. Hg (1025 hPa)
ob: KYKM 262153Z 02004KT 10SM CLR 19/01 A3029 RMK AO2 SLP256 T01940011
cycle: 22

<Enter to Close>
```


```
# Start weather system tray applet
(sleep 2 && \
yad --notification --image=weather-overcast \
 --text="Yakima, WA Weather" --no-middle \
 --command='xterm +sb -g 72x16-0+38 \
 -T "Yakima, WA Weather" \
 -e "/home/jsh/scripts/weather.sh"') &
```

A similiar script can be used to obtain a Terminal Area forecast:

```
#!/bin/sh
# This is a simple script that downloads current weather conditions and zone
# forecast from the National Weather Service and formats the output.
#
# To change the forecast zone, replace wa/waz027 with another forecast zone.
# See <http://weather.noaa.gov/pub/data/forecasts/zone/> for a list.
#
curl -sk http://tgftp.nws.noaa.gov/data/forecasts/zone/wa/waz027.txt| \
fold -w 78 -s
echo ""
printf "<Enter to Close>"; read nothing
```

Lastly, a script to run an animated gif of the 4 latest radar images using graphics/imagemagick


```
#!/bin/sh

# This is a simple script that downloads an animated gif of
# the latest 4 radar images
# This script is configured for the Pacific Northwest composite
#

# To change the site edit "PACNORTHWEST_loop.gif".

curl https://radar.weather.gov/ridge/standard/PACNORTHWEST_loop.gif | \
 animate -immutable -loop 0 -title "NorthWest Radar Loop"
```

Airports are by ICAO codes.  You can browse what is available here


----------



## graudeejs (Feb 15, 2018)

Here's trick how I attach my GELI encrypted disks using sysutils/password-store:

```
$ pass show geli/password/in/password-store | head -n 1 | sudo geli attach -p -k - /dev/da0
```

This way password is passed via stdin as keyfile for geli.
To initialize geli safely, first generate password with password store, then run something like:

```
$ pass show geli/password/in/password-store | head -n 1 | sudo geli init -P -K - /dev/da0
```

Also to ensure that I don't forget how to attach disk, I simply added command into comments of password store entry.

Note that if you're to save password in keyfile, ensure that it ends with newline since it's not stripped from command line


----------



## graudeejs (Feb 20, 2018)

If you're using ProtonVPN and ever tried to setup OpenVPN on FreeBSD you might notice that if you generate config for linux there are two lines that don't work on FreeBSD

```
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
```
A quick google search will unveil https://github.com/masterkorp/openvpn-update-resolv-conf, however my problem with this script is that it uses bash.

To solve this *bug*, I forked repo and rewrote code to work with sh on FreeBSD https://github.com/graudeejs/openvpn-update-resolv-conf-freebsd/blob/master/update-resolv-conf.sh


Warning. It's not fully tested as I didn't bother to test all possible usecases, however for my ProtonVPN setup it works like charm. If you have problems with it feel free to file a bug report in github.


----------



## Snurg (Feb 20, 2018)

When you just want to review all package notes in a clean formatted manner, without any "no maintainer" spam, you'll like my small perl script.
Usage: `showpkgnotes | less`.

Download here: https://github.com/kernschmelze/showpkgnotes


----------



## Wamphyre (Mar 6, 2018)

Hi! There's my FreeBSD scripts for automate some functions, like FAMP server or install an full-pledged XFCE desktop with nvidia drivers  https://github.com/Wamphyre/AutoTools


----------



## _martin (May 2, 2018)

Speaking of handy one-liners: from time to time I find myself in a single boot console, often without proper terminal settings and practically unable to use standard (vi) editor. That's where ed friend comes in very handy. Let's say I need to edit config file and change the line "Port 22" to "Port 666":

`printf "/^Port/s/Port 22/Port 666/\nw\nq" | ed -s test.conf`

Tested on FreeBSD, Linux, HP-UX and Solaris.


----------



## Sensucht94 (May 8, 2018)

some useful commands I always keep in my ~/.bin directory:

- uptime in mins:
`uptime | awk -F, '{sub(".*up ",x,$1);print $1}' | sed -e 's/^[ \t]*//'`

- installed package count:
`doas pkg info | wc -l | sed -e 's/^[ \t]*//'`

- zroot/ROOT/default free %:
`df -hk | egrep 'ROOT|/$' | awk '{print$5}'`

I have yet to find a way a easy way to measure free RAM percentage in FreeBSD, which doesn't involve operations between vm.stats.vm.v_*_count `sysctl` values. All the more I' m not sure I truly understood the relationship between inactive, free, wired and cached memory. NetBSD's mount_procfs(8) brings some additional nodes for compatibility with Linux, so as that when the pseudo-filesystem is mounted (default) , i can always rely on /proc/meminfo to grep all needed info, included free mem percentage with something like:
`$(awk -F ':|kB' '/MemFree:/ {printf $2}' /proc/meminfo) / 1024`

For FreeBSD however, I found a very cool script online, that  I'm going to upload immediately beneath (as _'mem.txt_')
To just get the free mem percentage, you can pipe it through awk and cut like that :
`mem.sh | awk 'FNR==18 {print $6}' | cut -c 1-3`


_Off-Topic_: graudeejs, looking at your profile photo, are you Ibara from OpenBSD? I'm a great fan of his ports including oksh, mg, and streamlink


----------



## jb_fvwm2 (May 10, 2018)

the freecolor port shows total/available ram... fwiw [does not work with all kernels I've tried on i386, though.]


----------



## ShelLuser (Nov 9, 2018)

"_For my ally is the Shell, and a powerful ally it is. Jobs creates it, makes them log. Its commands surround us and guide us. Scripting beings are we! Not those crude mouse clickers! You must use the Shell around you.. here, between mouse and keyboard. Even between...  the browser and the forum.._"

uhm..  I'm in that mood again 

I've messed with shell scripts a lot over the years and I'd even go as far as to state that the shells are the glue which keep our systems together. Alas, even though I've done plenty of scripting I'm also lazy at times. So when I had to process a list like this:


```
$ ls | sed -E 's/-[0-9]+\..*\txz//g' | uniq -cd                            
   2 boost-libs
   5 ffmpeg
   2 glib
   3 harfbuzz
   3 harfbuzz-icu
```
... I quickly resorted to /bin/csh because it could somehow grok the list much better:

```
$ for a in `cat list`; do echo $a | cut -w -f2; done
2
boost-libs
5
ffmpeg
2
glib
3
harfbuzz
3
harfbuzz-icu
```
If you try this out for yourself you'll notice that the cut command didn't do anything at all. Even using quotes around $a won't make a difference. The C shell on the other hand...

```
% foreach a ("`cat list`")
foreach? echo $a | cut -w -f2
foreach? end
boost-libs
ffmpeg
glib
harfbuzz
harfbuzz-icu
```
Change -f2 into -f1 and you get the amount of occurrences.

Now, I did Google this a few times and even though I did see IFS getting mentioned several times I never gave it too much thought, also because csh(1) never mentions it and because the given explanation was often plain out poor.

Well, today I finally dove into sh(1) and I figured it out 

IFS, or the Input Field Separator, determines what characters are to be used for "field splitting":


```
IFS           Input Field Separators.  The default value is <space>,
                   <tab>, and <newline> in that order.  This default also
                   applies if IFS is unset, but not if it is set to the empty
                   string.
<CUT>
     Embedded newlines before the end of the output are not
     removed; however, during field splitting, they may be translated into
     spaces depending on the value of IFS and the quoting that is in effect.
<CUT>
     Subsequently, a field is delimited by either

     1.   a non-whitespace character in IFS with any whitespace in IFS
          surrounding it, or

     2.   one or more whitespace characters in IFS.

     If a word ends with a non-whitespace character in IFS, there is no empty
     field after this character.
```
This seems all very vague and theoretical, I know, but stay with me for now. Also _very_ important to know is this:

```
Dollar-Single Quotes
             Enclosing characters between $' and ' preserves the literal
             meaning of all characters except backslashes and single quotes.
             A backslash introduces a C-style escape sequence:

             \n          Newline
```
It got me thinking...  SO:


```
#!/bin/sh

IFS=$'\n'

for a in `cat list`; do
        echo $a | cut -w -f2;
done
```
And here is the list again which I used:

```
2 boost-libs
   5 ffmpeg
   2 glib
   3 harfbuzz
   3 harfbuzz-icu
```
Try commenting out IFS and see what happens.

(edit): The key to this mystery is that if you read carefully you'll notice that <space> comes _before_ end of line. So, uhm, what do you think caused those indents before and after the numbers?

As mentioned: I know that IFS gets mentioned several times on the Net already, it's also why I got pointed towards it. But most of the given examples never bother to explain why it does what it does, and that is simply not good enough for me.

I don't care about working solutions until I know & understand what makes them tick. And now I do 

Hope this could be useful for some of you!


----------



## debguy (Nov 10, 2018)

# no # for a in `cat list`; do echo "$a" | cut -d' ' -f2 ; done

# don't do that because "echo" works differently on different unix so it's not wise to use echo to echo file text lines to text utilities (and the echo -e thing also isn't available on other unix).  use cat(1) or supply the file name to the utility.

# in general Never use $a in bash or csh.  use "$a" because if it's not in quotes: it may be INTERPRETED by the shell and end up running software you had no intent of running !  ouch!

# store your list in a file first and the following works

cat list | cut -d' ' -f2

# also, give -d' ' not -w, other unixes will not take -w.   apple imac bsd says:

*STANDARDS*
     The *cut* utility conforms to IEEE Std 1003.2-1992 (``POSIX.2'').

*HISTORY*
     A *cut* command appeared in AT&T System III UNIX

# while IFS works, it's more of a hastle and really you should restore IFS it unless your sure the script won't be sourced by another script.
IFS=$XIFS
IFS=$'\n'
# do something
IFS=$XIFS

# finally:  many would urge you to learn awk

cat list | awk '{print $2}'
ls -la | awk '{print $9}'

# but really you should use find if you want a list of file names because it's the right tool for admins to use in scripts

find . -type f -maxdepth 1

# but do NOT use this - because if you ever walk your script elsewhere you'll find -printf %f no longer works
# because not all unix support it (instead one prints out full info and selects fields with cut or awk)
find -type f -printf %f

# ls -1
# ls -1 seems to work but if your file system supports sockets mounts symbolics and case sensitivity (or rather non-sensitivity) is an issue, you can get in trouble if your not in a "simple place".  find let's avoid listing things the kernels show that aren't really files are aren't really located "here" (you have to see it's options for more info)


----------



## ShelLuser (Nov 10, 2018)

debguy said:


> # no # for a in `cat list`; do echo "$a" | cut -d' ' -f2 ; done
> 
> # don't do that because "echo" works differently on different unix so it's not wise


You _do_ realize what OS this forum is all about, right?  Why on earth would I bother myself what other environments might do? Not to mention that your motivation is actually quite off too, this has _nothing_ to do with the OS itself but more so with the shell you're using.

And /bin/sh ('Bourne') is pretty much a set out standard within this field. I've been using this specific construction dating back to the days of SunOS around 1995 or so and have continued to use this throughout dozens of shell scripts on SunOS / Solaris, HpUx, Linux and several BSD variants, never running into problems.

At best it can be changed so that the carrots get exchanged for $() which can make it a little more readable, but the rest of your argumentation is quite off in my opinion.



debguy said:


> # in general Never use $a in bash or csh.


This was never about bash nor csh in the first place. (edit) Also your argumentation is once again quite off; interpretation would only happen when you'd use the variable outside the scope of anything else, which is obviously not very efficient to begin with.

But the funny part is that even quotes won't make too much of a difference because although your _current_ shell instance may not interpret the variable, the shell that gets called will.


```
#!/bin/sh

a="echo m000"

$a
"$a"
```
I'm sure this doesn't give you the results you'd expect 



debguy said:


> # store your list in a file first and the following works


lol!

Sorry, but I can't take this comment too seriously. That would only create more unnecessary clutter, add extra unneeded complexity and in general would actually tax the system more, depending on what you're doing.

(edit2) You share a lot of dry theory but no compelling arguments which actually make some sense to me. As I mentioned earlier: this is FreeBSD we're talking about, so commenting that it's best not to use certain commandline parameters just because of other operating systems is simply absurd IMO.


----------



## shkhln (Nov 10, 2018)

ShelLuser said:


> You _do_ realize what OS this forum is all about, right?


No, of course he doesn't.


----------



## jrm@ (Nov 10, 2018)

debguy said:


> cat list | cut -d' ' -f2


There's no need to `cat ... | ...`.

```
cut -d' '-f2 list
```



debguy said:


> cat list | awk '{print $2}'


Same.

```
awk '{print $2}' list
```


----------



## ShelLuser (Nov 10, 2018)

jrm@ said:


> There's no need to `cat ... | ...`.
> 
> ```
> awk '{print $2}' list
> ```


Now that's an argument I _can_ appreciate, and you're completely right. awk is one of those things I still need to study a lot more myself. Have been using it in the past several times (mostly to process config files and at one time to retrieve the name of any configured jails) but very sparsely.


----------



## olli@ (Nov 11, 2018)

Allow me to comment …


ShelLuser said:


> ```
> $ for a in `cat list`; do echo $a | cut -w -f2; done
> 2
> boost-libs
> ...


To get the second word from a list of two-word lines, the correct way is actually also quite simple:

```
$ while read a b; do echo $b; done < list
boost-libs
ffmpeg
glib
harfbuzz
harfbuzz-icu
```
No need to use `cut` or any other external commands.
Also note that the use of backquotes (a.k.a. backticks) is discouraged for several reasons. Better use `$(...)` notation for command substitution.

I think that csh exists in FreeBSD's base system purely for historic reasons, but it shouldn't actually be used for anything, especially not for scripting. If you're curious, ask the search engine of your choice for “csh programming considered harmful”. ;-)

Apart from that, if a task grows sufficiently complex that you're forced to play with IFS, `eval` and other evil things, you should rather implement it with a more capable scripting or programming language, such as awk, Python or whatever.


----------



## ShelLuser (Nov 11, 2018)

olli@ said:


> I think that csh exists in FreeBSD's base system purely for historic reasons, but it shouldn't actually be used for anything, especially not for scripting.


Well, I definitely disagree with that. I've been using csh as the root shell for pretty much as long as I used FreeBSD and I think there's a major advantage in doing so.

Csh is fully aimed at interaction. A very good example can be seen above when I used a "for a in..." with sh an its "foreach a" counterpart in csh. The latter allows ("softly forces"?) you to cut up all your commands into smaller pieces and provide them one at a time. This makes it much easier to carefully check all your commands to verify that they're really going to do what you intended.

With sh (and most other bourne-like shells) not so much; when you enter enough commands then the first part of your line will eventually disappear from the screen and that's it.

As to scripting...



olli@ said:


> If you're curious, ask the search engine of your choice for “csh programming considered harmful”. ;-)


I read a few posts (I was familiar with some already) but it all boils down to "_It's harmful because it works different than bourne_", to which I can only reply "_Well, duh!_". I can't help but pick that up as people blaming the tool for its (in)abilities. And then you have plenty of people blindly copying that list of examples (they're not real arguments) as if it somehow holds any value within the context of good vs. bad. Yet it doesn't: it all boils down to csh behaving different than other shells. There's a solution to that and it's called a manual 

And csh also has plenty of advantages. When I test something then it makes sense to have only stdout ('|') _or_ stdout + stderr ('|&') because who cares about them separately? An error is nothing without output ('context') and it gets hard to find a problem without errors   Of course that changes when you're scripting.

And well...  in the list you can read about an issue with `kill -l `cat foo`` vs. `/bin/kill -l `cat foo``. It doesn't help that I can't reproduce this on csh myself, but it gets worse when I notice that other shells behave in pretty much the same uncanny way:


```
peter@zefiris:/home/peter $ echo $0
-/usr/local/bin/ksh
peter@zefiris:/home/peter $ kill -l `cat bugzilla.png` 
: bad numberin/ksh: kill: PNG
peter@zefiris:/home/peter $ /bin/kill -l `cat bugzilla.png`
usage: kill [-s signal_name] pid ...
       kill -l [exit_status]
       kill -signal_name pid ...
       kill -signal_number pid ...
peter@zefiris:/home/peter $ csh -l
Nice bash prompt: PS1='(\[$(tput md)\]\t <\w>\[$(tput me)\]) $(echo $?) \$ '
                -- Mathieu <mathieu@hal.interactionvirtuelle.com>
% kill -l `cat bugzilla.png`
HUP INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE ALRM TERM URG STOP 
TSTP CONT CHLD TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2 LWP 
% /bin/kill -l `cat bugzilla.png`
usage: kill [-s signal_name] pid ...
       kill -l [exit_status]
       kill -signal_name pid ...
       kill -signal_number pid ...
% sh -
$ kill -l `cat bugzilla.png`
usage: kill [-s signal_name] pid ...
       kill -l [exit_status]
       kill -signal_name pid ...
       kill -signal_number pid ...
$ /bin/kill -l `cat bugzilla.png`
usage: kill [-s signal_name] pid ...
       kill -l [exit_status]
       kill -signal_name pid ...
       kill -signal_number pid ...
```
Each to their own but I'd say that csh gave the most reasonable response in this scenario  And yes, I realize that the list is most likely dated, but I cannot help but wonder how the other shells behaved back then.

Now, don't get me wrong: I'm definitely not advocating csh scripting. Simply because I'm already familiar with plenty of those quirks. As I mentioned earlier: csh excels as an interactive tool but it's definitely not the best for scripting, sh is much more useful. But actually considering it harmful is IMO ridiculous; it's not the tool which causes damage, but the tool that's using it.



olli@ said:


> Apart from that, if a task grows sufficiently complex that you're forced to play with IFS, `eval` and other evil things, you should rather implement it with a more capable scripting or programming language, such as awk, Python or whatever.


That I fully agree with   Still, sometimes for hobby projects it can be fun to take the shell into extremes and still get work done. Also because sometimes (not always) you'll have less overhead when using the shell itself than a full blown scripting language.

Even so... I really need to finally spend more time on learning awk 

Thanks again for your comments!


----------



## olli@ (Nov 11, 2018)

ShelLuser said:


> Well, I definitely disagree with that. I've been using csh as the root shell for pretty much as long as I used FreeBSD and I think there's a major advantage in doing so.


When I started with UNIX in general (that was before FreeBSD even existed), I used csh as my login shell – actually tcsh, to be exact¹. But at some point its deficiencies started to annoy me, and I disliked the fact I couldn't simply paste parts from a shell script to the command line in order to try them out, modify them until they work, then paste them back into the shell script. At that point I decided it would be beneficial to switch to a bourne shell as my login shell. The only question was: which one? Back at that time, FreeBSD's /bin/sh was not really good for interactive work (it didn't have a history, for example). Some of my friends used bash, so I tried it. But then I discovered zsh, gave it a try, too, and liked it much better. Since then, zsh is my login shell.

¹ Note: FreeBSD's /bin/csh is not a real csh, but tcsh.


> Csh is fully aimed at interaction. A very good example can be seen above when I used a "for a in..." with sh an its "foreach a" counterpart in csh. The latter allows ("softly forces"?) you to cut up all your commands into smaller pieces and provide them one at a time. This makes it much easier to carefully check all your commands to verify that they're really going to do what you intended.


Have you actually tried it? You _can_ do the very same in bourne shell. But you're not forced to do it.


> With sh (and most other bourne-like shells) not so much; when you enter enough commands then the first part of your line will eventually disappear from the screen and that's it.


Huh? That's simply _not_ true. You can enter as much as fits into your terminal window's width + height. Although it's probably not a good idea to construct commands that large in a single interactive line. But you can do it if you want.

I'm not going to comment the other things you wrote … Let's just agree that we disagree. 


> Even so... I really need to finally spend more time on learning awk


That's definitely a good idea. Many people think that awk is only good for cutting rows (like `'{print $1}'`) and are unaware that it is a full-fledged programming language. In fact you can write scripts in pure awk, just use `#!/usr/bin/awk -f` as the first line. (You can write pure sed scripts, too, of course …)

By the way, I have an alias `root="su -m root"`, so whenever I type `root`, I get a root prompt with the same shell as my login shell (i.e. zsh in my case) without actually having to modify root's login shell (which I leave at /bin/csh because it is never used anyway).


----------



## ShelLuser (Nov 11, 2018)

(about parts of the command line disappearing)



olli@ said:


> Huh? That's simply _not_ true. You can enter as much as fits into your terminal window's width + height.


You're right about sh, that was a mistake on my part, but it seems to depend on the shell you're using. I tested it on my laptop just now and noticed a difference in behavior between ksh (which is my personal favorite) and sh (where this didn't happen). Just for context, this is the behavior I meant:






I'm not sure from mind what causes this, come to think of it I suppose it could also be an effect of setting up a specific prompt, but what you see here is the end of `for a in `ls | uniq -wd | tee test` (useless command, just for testing).

Something for my never ending todo list on things to further examine & study


----------



## aragats (Nov 12, 2018)

Sensucht94 said:


> some useful commands I always keep in my ~/.bin directory:
> 
> - uptime in mins:
> uptime | awk -F, '{sub(".*up ",x,$1);print $1}' | sed -e 's/^[ \t]*//'
> ...


Sensucht94 , please keep in mind that sed doesn't understand `\t`, that's a GNU extension. To catch both spaces and tabs you can use `[[:blank:]]` (or use gsed in your scripts instead).


----------



## olli@ (Nov 12, 2018)

ShelLuser said:


> (about parts of the command line disappearing)
> 
> You're right about sh, that was a mistake on my part, but it seems to depend on the shell you're using. I tested it on my laptop just now and noticed a difference in behavior between ksh (which is my personal favorite) and sh (where this didn't happen). Just for context, this is the behavior I meant:
> 
> ...


Ok, I see what you mean. I can confirm that it does not happen with FreeBSD's /bin/sh nor bash or zsh. At least not with the default settings. In zsh _everything_ can be configured somewhow, so I wouldn't be surprised if you can enable such a “single-line” behavior if you want.

Out of curiosity, why is ksh your favorite? And which one of the various implementations? I mean, ksh93 is supposed to be the most standards-compliant, while mksh and oksh are somewhat more “modern” and have more features. However, their usability and features fall clearly behind both bash and zsh. The only trade-off in zsh is the fact that its syntax for creating co-processes differs from POSIX (even though zsh can emulate ksh in every other regard). That's a rarely used feature, though.


----------



## aragats (Nov 12, 2018)

ShelLuser said:


> (about parts of the command line disappearing)
> ....
> I'm not sure from mind what causes this, come to think of it I suppose it could also be an effect of setting up a specific prompt...


I don't see such thing with ksh93 in urxvt.
ShelLuser , since you use Xorg, have you tried running `resize` when such things happen?
I noticed that sometimes terminals get screwed up by "bad outputs" of certain commands.


----------



## ShelLuser (Nov 12, 2018)

Thanks for your comments, both of you 



olli@ said:


> Out of curiosity, why is ksh your favorite? And which one of the various implementations?


I use shells/pdksh on all my servers, and the 'why' part has everything to do with SunOS / Solaris. There is no rational reasoning other than ksh being the standard on Sun Solaris and that was the very first Unix environment I learned to operate (and I loved every part of it).

Around the 90's during my internship within Olivetti computers did I learn about this 'magical' operating system called Unix which could outperform Windows on every possible geek level. Transporting files between PC's? No need for floppies nor a special parallel cable with laplink or Norton Commander. Instead even a serial cable would do and you'd be able to simply communicate between those machines with nothing other than the Unix OS itself. Even Windows 3.11 couldn't pull that off!

Learned about Linux (RedHat 'Picasso') and dove in head first.

So when I became a sysadmin at my first job and suddenly discovered that a sub-group within our company used a Sun Sparcstation running Sun Solaris ("Unix") plus Smartstream (database server) while they were having issues I knew exactly what to do. Well, I didn't but I knew `man man`, learned about catman and then apropos then and there. Fixed the network hiatus by switching the server from DHCP client (provided by a flakey Novell server) to a static IP and everyone was happy. So happy that I was sent onto 2 Sun Solaris training camps, paid for by said company. That was the beginning of the end 

I didn't switch from Linux to FreeBSD, I switched from Solaris 10/x86 to FreeBSD 

Back then (around 2009 I think?) FreeBSD was the perfect Solaris replacement for me; UFS & ZFS, Jails vs. Zones, ipf (Solaris firewall) and a sane user land.

I exchanged ipfilter for pf last year or so, but I'm still a die hard Korn shell user 

Note that I don't use it for scripting or such, only interaction. Mine even runs in vi mode by default, I love it:


```
peter@zefiris:/home/peter $ cat .kshrc
if [ "`basename ${0#-}`" == "ksh" ]; then
   set -o posix -o braceexpand -o vi -o vi-tabcomplete;
   PS1="`whoami`@`hostname -s`:\${PWD} \$ ";
fi
```
Very important detail is that for me it's not only about work, I also actually enjoy working with this stuff.

I really should change my PS1 sometime, these days you can swap out your home for ~ or make it cut longer pathlines into smaller bits but I never took the time to do so and just kept using what I already had & once learned 

Sorry for a brief ramble there, but yah 



aragats said:


> ShelLuser , since you use Xorg, have you tried running `resize` when such things happen?
> I noticed that sometimes terminals get screwed up by "bad outputs" of certain commands.


No, never bothered with resize(1) (did look it up as you can tell  ). But this has nothing to do with X directly though, this also happens if I'm on a regular console (I never automatically log onto the GUI).

But it's shell related. As olli@ mentioned above; this doesn't happen with sh (which I also tried) but more so with ksh. Still, it doesn't bother me, also because my vi mode allows to be move back and forth onto such a commandline with easy (escape ^; done).


----------



## chrbr (Nov 13, 2018)

ShelLuser said:


> Mine even runs in vi mode by default, I love it


I am a hobbyist with respect to IT. But this is why I really like shells/ksh93. I have not tried shell/pdksh yet. Learning some key bindings and use them for many tools is marvelous.


----------



## olli@ (Nov 14, 2018)

chrbr said:


> I am a hobbyist with respect to IT. But this is why I really like shells/ksh93. I have not tried shell/pdksh yet. Learning some key bindings and use them for many tools is marvelous.


But vi-mode is not unique to ksh. _All_ common shells support vi-mode line editing. bash and zsh do, and even FreeBSD's /bin/sh supports it (even though it's otherwise not very well-suited for interactive use).


----------



## chrbr (Nov 14, 2018)

olli@ said:


> But vi-mode is not unique to ksh. _All_ common shells support vi-mode line editing.


May be this feature is not promoted that much. One benchmark I found useful is http://hyperpolyglot.org/unix-shells. And then there are tons of howtodo documents for each shell which one could go through.


----------



## k.jacker (Dec 10, 2018)

If anyone has ever tried to format multimedia/mplayer's "ICY Info" output strings from a script, has maybe grown some grey hair.
There are a lot of examples on the web using grep, cut, awk and sed, and that's what I was using, too.
Still it had some weaknesses.

Today I stumbled over some of my own examples from earlier this year, where I was learning to use back references.

What I use now, has become so short and simple, with no weaknesses anymore, I'd like to share it.

```
mplayer -msglevel all=0:demuxer=4 <url to radio stream> | grep --line-buffered -oe "\([\']\)[[:print:]]*\1"
```
Nice, tmux statusline ready output 
_'Dynoro feat. Gigi D'Agostino - In My Mind'
'Udo Lindenberg - Cello (feat. Clueso)'
'www.antennemv.de'
'Depeche Mode - People Are People'
'Milow - Lay Your Worry Down (feat. Matt Simons)'
'The Avener - Fade Out Lines'
'Jason Mraz - Have It All'
'R.E.M. - Losing My Religion'
'Adele - Someone Like You'_

What the backreference does is, it greps everything between the first and the last single quote from the string:
ICY Info: StreamTitle='Dynoro feat. Gigi D'Agostino - In My Mind';

Redirect the output to a file and add the following to ~/.tmux conf

```
set -g status-left '#(tail -n1 /tmp/<filename>)'
```


----------



## Sensucht94 (Dec 11, 2018)

pdksh, and all its idependent derivatives (mksh, GNU ksh, OpenBSD ksh -oksh-, NetBSD ksh,  AmigaOS SKsh) are originally born as free AT&T ksh88 clones, the way Linux is Unix clone (completely written from scratch, different at its core, compatible at its surface); the ksh one can find on commercial Unices, is  AT&T ksh93, a new overall reshaped and improved version of ksh88, first released in '94, opensource  under Eclipse Public License as of 2005, Illumos default system interpreter, developed until 2014 when the last version was released, and presumably now discontinued.
dtksh (CDE's shell, used also in the dtlogin Xsession script) and tksh are ksh93 derivatives providing shell-level mapping for Motif and Tk widget toolkits respectively. rksh is ksh93 acting in restricted mode

Although many patches providing cross-compatibility with new ksh93 additions were submitted to the various pksh versions  throughtout the years, pdksh derivatives and ksh93 are not fully compatible, while pdksh derivatives usually are with one another

Generally speaking ksh93 is more complex (have a look at sources on github), one may say bloated;
Of all the pdksh derivatives, mksh is the most featured, providing bash/zsh -like extentions, while oksh is the most stripped down, clean, fast, but also barebones

None of those shells are POSIX-compliant by default (in spite of their significantly stronger adherence to POSIX compared to bash), but can operate in POSIX mode (set -o posix), which is what they do when invoked as /bin/sh


----------



## Vull (Dec 11, 2018)

I used the AIX version of ksh for years in my work environment which was dominated by AIX, SCO Openserver 5, and Red Hat 6.2, and it was my favorite shell. Here's an old script I wrote for changing the PS1 prompt, just to remind myself and other programmers which machine we had telnetted into, and to put the pathname in the prompt, which still wasn't all that common a thing in the 90s, and SCO still had just the "$ " or "# " prompts, and lacked the capability of putting the `pwd` present working directory pathname in the prompt. It's a bit crude and I'm almost ashamed to admit I wrote it, but it worked then and still works now. I no longer use AIX, SCO, or Red Hat, and have since modified it to work on FreeBSD and MacOS X 10.5.8, but it still has some of the old residue from those original three systems. Originally it was intended to use different sets of braces in the set {},[],<> to indicate the "flavor" of the OS, and it still has some of that in there too...

Edited March 12, 2019 - this is the latest improved version as just tested on freebsd 12.0-RELEASE, Debian 9.6, and Mac OS X 10.5.8 - this version uses `id -u` to detect if a user has used `su -m` to gain super-user status in FreeBSD, and accordingly shows "#" instead of "$" at the end of the prompt, even when the USER and HOME environment variables are neither root nor /root (assuming that the user's default SHELL Is /bin/sh).

```
#!/bin/sh
# wasatps1 - format PS1 shell prompts for bash, ksh, or sh shells
# 2019-03-12 t jch
#
# --- Usage:  PS1=`wasatps1`;export PS1
#
# --- Show $PWD (print working directory) if shell is capable (bash or ksh).
# --- Show hostname or user name as specified locally by SHOWHOST and SHOWUSER.
# --- Indicate if user is superuser by "$" (user) or "#" (super-user) suffix.
#
SHOWHOST=1 #--- 0=don't show hostname in shell prompt, 1=show it.
SHOWUSER=1 #--- 0=don't show username in shell prompt, 1=show it.
PROMPTLINES=1 #--- 1=1 line prompt, 2=2 line prompt
              #--- NOTE: sh doesn't interpret "\n" and so won't display 2 lines
#
#--- Only interpret bash, ksh, or sh shells. While checking the shell name, also

#--- set CANPWD=1 if shell prompt is capable of displaying the working directory

if [ "`echo $SHELL |grep -c /bash`" != "0" ];then
        THISSH=bash
        CANPWD=1
elif [ "`echo $SHELL |grep -c /ksh`" != "0" ];then
        THISSH=ksh
        CANPWD=1
elif [ "`echo $SHELL |grep -c /sh`" != "0" ];then
        THISSH=sh
        CANPWD=1
else #--- if neither bash, ksh, or sh is the shell, return $PS1 unchanged
        echo "$PS1"
        exit 0
fi
#--- Sniff for AIX, Linux, SCO Openserver, Mac OSX, and FreeBSD systems. Also
#--- set ISSUPER=1 if shell is running as super-user.
ISSUPER=0
if [ -d /usr/lpp/bos ];then
        FLAVOR=aix #--- IBM AIX operating system for RISC system architecture
        PREFIX=\< ; SUFFIX=\>
        if [ "$LOGIN" = "root" ];then ISSUPER=1 ; fi
elif [ "`which freebsd-version`" != "" ];then
        FLAVOR=freebsd
        PREFIX=\( ; SUFFIX=\)
        #if [ "$HOME" = "/root" ]||[ "$USER" = "root" ];then ISSUPER=1; fi
        if [ "`id -u`" = "0" ]; then ISSUPER=1; fi
elif [ "`ls /boot/vmlin* 2>/dev/null`" != "" ];then
        FLAVOR=linux #--- presumably Red Hat Linux 6.2 or newer ---#
        PREFIX=\[ ; SUFFIX=\]
        if [ "$HOME" = "/root" ];then ISSUPER=1 ; fi
elif [ -d /var/opt/K/SCO ];then
        FLAVOR=sco #--- presumably SCO Unix OpenServer 5 or better ---#
        PREFIX=\( ; SUFFIX=\)
        if [ "`env |grep '_=' |grep -c su`" = "1" ];then ISSUPER=1 ; fi
        if [ "$PS1" = "# " ]||[ "$LOGNAME" = "root" ];then ISSUPER=1 ; fi
elif [ -f /mach_kernel ];then
        FLAVOR=mac #--- presumably Apple Mac OS X or higher ---#
        PREFIX=\{ ; SUFFIX=\}
        if [ "$HOME" = "/var/root" ];then ISSUPER=1; fi
else #--- if none of the above systems, return $PS1 unchanged & exit normally
        echo "$PS1"
        exit 0
fi
#--- Get host name if specified, but strip off any domain name suffixes.
if [ "$SHOWHOST" != "0" ];then
        SHOWHOST=`hostname`
        SHOWHOST=`echo $SHOWHOST |awk 'BEGIN { FS = "." } { printf("%s",$1) }'`
fi
#--- format the shell prompt for the host, shell, and super-user level at hand
if [ "$SHOWUSER" != "0" ] || [ "$SHOWHOST" != "0" ];then
        PS1=$PREFIX; else PS1=
fi
if [ "$THISSH" = "bash" ];then
        if [ "$SHOWUSER" != "0" ];then PS1=$PS1"\u" ; fi
        if [ "$SHOWHOST" != "0" ];then PS1=$PS1"@\h" ; fi
else
        if [ "$SHOWUSER" != "0" ];then PS1=$PS1$LOGNAME; fi
        if [ "$SHOWHOST" != "0" ];then PS1=$PS1"@"$SHOWHOST; fi
fi
if [ "$CANPWD" != "0" ];then
        if [ "$SHOWUSER" != "0" ]||[ "$SHOWHOST" != "0" ];then
                PS1=$PS1" "
        fi
        if [ "$THISSH" = "sh" ];then
                PS1=$PS1"\w"
        else
                PS1=$PS1"\${PWD}"
        fi
fi
if [ "$SHOWUSER" != "0" ] || [ "$SHOWHOST" != "0" ];then
        PS1=$PS1$SUFFIX
fi
if [ $PROMPTLINES -eq 2 ];then PS1=$PS1"\n"; fi

if [ "$ISSUPER" != "0" ];then
        PS1=$PS1"# "
else
        PS1=$PS1"$ "
fi
echo "$PS1"
exit 0
```


----------



## Vull (Dec 20, 2018)

Self-extracting installer script:

The "exex" script has 2 functions. If it's executed with command line arguments, it attempts to perform the Create() function, and if it has no command line arguments, it attempts to perform the Extract-and-Execute function. This has been tested on FreeBSD 11.2 and 12.0, and on Debian 9.5 and 9.6.

  1. The "Create()" function creates a single executable file by concatenating 3 separate files, one after the other:
  1. A. The first file included in the self-extracting executable is the exex script itself.
  1. B. The second file included in the self-extracting executable is a separate script which will run right after the archive is extracted. In the example provided here, it will unzip the archive and start the installation of the software in the archive.
  1. C. The third file included in the self-extracting executable is the archive itself.

  2. The "Extract()" function is the function which extracts the archive from the concatenated file. After the extraction has been done, the 2nd file will be executed automatically. The automatic execution depends on the fact that the exex script has no 'exit' statement, and therefore, since the 2nd file comes right after the first, control will pass immediately from the last executed statement in the first file to the first executable statement in the 2nd file.  For further documentation please refer to the comments in the two scripts. The first script is the exex file itself, and the 2nd script is an example of what can be done automatically after the archive has been extracted.

exex

```
#!/bin/sh
# 2018-12-19 w jch - modified for better posix compliance
#-------------------------------------------------------------------------------
# exex - create the SXE (mode=c), or (ex)tract & (ex)ecute the SXE (mode=x)
# ----   ------     ---  ------       --          --           ---  ------
# SXE = (S)elf-e(X)tracting-(E)xecutable script file

Create() { #--- Create the whole self-extracting archive and executable script.

  #--- get the file size of this file, which will be the first file in the sxe,

  size1=`ls -l $0 |awk 'BEGIN{FS=" "}{printf("%s",$5)}'`

  #-- and the size of the user-provided script file, which will be the 2nd file,

  size2=`ls -l $script |awk 'BEGIN{FS=" "}{printf("%s",$5)}'`
  
  #--- and the size of the user-provided archive, which will be the 3rd file

  # size3=`ls -l $archive |awk 'BEGIN{FS=" "}{printf("%s",$5)}'`

  #--- NOTE: we don't actually need to know size3, hah, so I commented it out.

  #--- Build a candidate line 2, which will be interpreted as a comment when
  #--- the combined script files run. The two scripts will execute one after the
  #--- other, like a single script. The size info line 2 comes right after the
  #--- shebang line, i.e., the line that says: "#!/bin/sh" ... The magical
  #--- importance of the inserted 2nd line is that it provides info to the
  #--- Extract() function, as to exactly where the user-provided archive file
  #--- begins, so it can be extracted from the sxe, and made into a usable
  #--- copy of the original archive. Thus, it must also contain the name of that
  #--- original user-provided archive. This Create() function will also insert
  #--- an "exit 0" at the end of the user provided script file, so the shell
  #--- won't try to execute the archive, which will be tucked in this file when
  #--- the exex script and the user provided script are executed together, as
  #--- one. The shell will interpret the two scripts together in one pass, like
  #--- they were a single script, and that's what makes it "self-executing."

  exitcommand="exit 0"    #--- The actual length of this line will be 7,
  # exitcommandlength=7   #--- 6 for the characters, plus 1 for the "\n" char.

  #--- Now begins a series of approximations of the exact offset of the archive.

  offset=$(($size1+$size2+7+4+${#archive})); # We know where the 7
  #--- in this offset sum came from, and the 4 in the same calculation is for
  #--- the length of the 3 # chars and the \n in the line 2 info comment. Then
  #--- we add the length of the NAME of the archive file, NOT the length, or
  #--- the size, of the actual archive file, because the name of the file will
  #--- be the 2nd item of info in the info comment line.
  
  #--- Now the 2nd, closer approximation: The problem is the decimal string len.
  offset2=$(($offset+${#offset})) #--- Add string length of offset.
  offslen=${#offset} #--- The approx. length of the decimal string.
  offslen2=${#offset2} #--- offslen is 1 estimate, offslen2, closer

  #- Make offslen2 the EXACT offset, after 1st seeing if the length "rolls over"
  #- (like speedometer mileage), for example, 999 is 3 digits, 1000 is 4 digits.

  if [ $offslen2 -gt $offslen ]; then $offset2=$(($offset2+1)); fi
  line2='#'$offset2'#'$archive"#" #--- Now, finally, offset2 = the exact offset

  # Oh I know, I could've just used a few # chars for padding, but it was fun:)!

  #--- Create a temporary filename for the tmp directory,

  tmpf=$HOME/grip/tmp/exexarchive.`wasat.who` #( wasat.who = pts.0, tty1, etc.,)
                                              #( something unique to this user.)

  #--- add the first line of this file (the shebang line) to the temporary file,

  line1=`awk 'NR==1{print $0}' $0` #(Select NR (Number of Record)=1,which means)
                                   #(the 1st line. (R)ecord=row, (F)ield=column)
  echo $line1 > $tmpf

  #--- followed by the 2nd info or comment line, which we need to insert, so the
  #--- Extract() function can use that info, and will know where to find it,

  echo $line2 >> $tmpf

  #--- Now, add lines 2 through the end of file, of the exex file, after line 2,

  tail -n +2 $0 >> $tmpf

  #--- and then add all the lines of the user supplied script file after that,

  cat $script >> $tmpf

  #--- and add the exit 0 command after the user supplied script, just in case,
  #--- because we wouldn't want the shell interpreter interpreting the archive.

  echo $exitcommand >> $tmpf

  #--- and add the archive file,

  cat $archive >> $tmpf

  #--- and rename it, at the same time moving to the path specified in the name,

  mv $tmpf $sxe
  chmod +x $sxe #--- and then, finally, make the whole file executable.

  echo 'Finished creating "'$sxe'"'
}

Extract() { #--- Extract the user-provided archive file, and then the 2nd part
            #--- of this file will execute, right after this function executes.

  #--- The shell interpreter's timing considerations will make the 2nd script
  #--- wait for the archive to be extracted, just like we have to wait for a
  #--- command to finish before the shell shows us the next command prompt.

  line2=`head -n 2 $0 |awk 'NR==2{print $0}'`
  offset=`echo $line2 |awk 'BEGIN{FS="#"}{printf("%s",$2)}'`
  archive=`echo $line2 |awk 'BEGIN{FS="#"}{printf("%s",$3)}'`
  if [ ! -f $archive ]; then
    tail -c +$(($offset+1)) $0 > $archive
  fi
}

Syntax() { #--- Complain about syntax errors and/or any type of errors, & exit.

  if [ "$mes" != "" ]; then
    echo
    echo "Error:  *** "$mes" ***"
  fi
  echo
  echo "Syntax:"
  echo "  exex scriptFile archiveFile nameForNewSelfExtractingExecutable"
  echo
  exit 1
}

#--- ma(in lo)gic

#--- Determine if we're running in create mode, or in extract and execute mode.

mode= #--- if filename is exex, run in create mode, otherwise, use ex & ex mode

mes= #--- error message for the Syntax() function

name=`echo $0 |awk 'BEGIN{FS="/"}{printf("%s",$NF)}'` #--- this filename

if [ "$name" = "exex" ]; then mode=c; else mode=x; fi

case "$mode" in

  ("c") #--- Create the archive

    #--- First check the command line arguments.
    exex=$0
    script=$1
    archive=$2
    sxe=$3 #--- S.X.E. is bad language for (S)elf e(X)ecuting (E)xecutable.

    if [ "$sxe" = "" ]; then Syntax; #--- If last one is empty all 3 are empty.
    elif [ ! -f $script ]; then
      mes='Script file: "'$script'" not found.'; Syntax
    elif [ ! -f $archive ]; then
      mes='Archive file: "'$archive'" not found.'; Syntax
    elif [ -f $sxe ]; then
      mes='Target file: "'$sxe'" already exists.'; Syntax 
    fi

    Create
     ;;

  ("x") #--- Extract the user-provided archive file, which is file section 3 in
        #--- this weird file, and then let the shell interpreter start
        #--- interpretting the user-provided script, which is file section 2.
        #--- We are now close to the end of file section 1. Thanks for visiting.

    Extract
     ;;
  (*) ;;
esac

#--- PROGRAMMER(S): THIS IS IMPORTANT! Do NOT add an exit command, and PLEASE,

# exit 0 #--- PLEASE, DON"T uncomment THIS line, or the user's script file
#        won't be executed! Which would thwart the whole purpose of this file.

#--- BECAUSE: we want the two scripts to run together, like a single script.
#-------------------------------------------------------------------------------
```

execute-install

```
#!/bin/sh
# execute-install - bootstrap script for self-extracting installer which s.b.
#   created by the non-root user running exex w/ this 2 step command sequence:
#
# cd $HOME
# exex grip/install/freebsd11.2.d/execute-install xfer.tar install-wasat
#
# Note: this is not an executable script, but rather, install-wasat will be.

# 2018-8-30 h 081 jch |# 2018-8-31 f 079 jch # 2018-9-16 n 088 jch
# 2018-10-15 m 094 jch |# 2018-10-20 m 094 jch |# 2018-11-3 s jch
# 2018-11-24 s jch - from grip/install/debian9.5.d -> grip/install/freebsd11.2.d

dv='11.2'
installdir='grip/install/freebsd'$dv'.d'
subnet=dashnet

oldpath=`pwd`
cd $HOME
#--- Check if system is partially installed (and still needs to have setup done)

echo "Checking if system is already (partially) installed ... "

h=/usr/local/www/apache24/data
if [ -f $h/wasat/setup-wasat.php ]; then
  DISPLAY=:0; export DISPLAY

  firefox "https://`hostname`.$subnet/wasat/setup-wasat.php" &

  cd $oldpath
  exit 0
fi
#--- Check if system appears to be completely or partly/unsuccessfully installed

if [ -d $h/wasat ]||[ -d $HOME/grip ]; then
  echo
  if [ -d $h/wasat ]; then
    echo 'Your system appears to be already installed in "'$h'/wasat/".'
  else
    echo "Your system appears to be partially installed."
    echo "There is a 'grip' directory in your home directory."
  fi
  cd $oldpath
  exit 0
fi
#--- Start unpacking the xfer.tar archive

echo -n "... Preparing to install the pre-packaged software ... "

tar -xf xfer.tar
tar -xzf xfer/grip.tar.gz
if [ ! -d $HOME/Desktop ];then mkdir $HOME/Desktop; chmod 700 $HOME/Desktop; fi
if [ ! -d $HOME/Desktop/0 ]; then mkdir $HOME/Desktop/0; fi
if [ "`ls xfer/wasat* 2>/dev/null`" != "" ]; then
  cp -p xfer/wasat* Desktop/0/
fi
echo
#--- Execute the install script

echo "... Starting the installation process ..."

$installdir/install |tee $installdir/install.log

inp=
if [ -f $h/wasat/setup-wasat.php ]; then
  echo
  while [ "$inp" != "y" ]&&[ "$inp" != "n" ];do
    echo -n "Would you like to continue with the setup now? [y/n] "; read inp;
    if [ "$inp" != "" ]; then inp=`echo $inp | tr [:upper:] [:lower:]`; fi
    case "$inp" in ("yes") inp=y;; ("no") inp=n;; ("y");; ("n");;
      (*) echo "Please answer yes or no (or y or n)."; inp="";;
    esac
  done
  if [ "$inp" = "y" ]; then
    echo "Launching the setup program now..."
    DISPLAY=:0; export DISPLAY
    firefox "https://`hostname`.$subnet/wasat/setup-wasat.php" &

    #--- message to keep terminal open in case installer was desktop-launched
    echo
    echo "Please leave this Terminal open until your Firefox session is"
    echo "closed, or your Firefox session may also be suddenly closed."
    echo
  fi
fi
cd $oldpath
exit 0
```


----------



## Vull (Jan 19, 2019)

Shell script to display FreeBSD package dependencies recursively:


```
#!/bin/sh
# pkg-dependencies - recursively display package dependencies / FreeBSD 12.0R
# 2019-1-18 f jch

# Uses a /tmp dir. work file to avoid listing the same packages more than once.
# May be interrupted with CTRL-C

trap Cleanup 1 2 3 6

Cleanup() {
  #-- delete the work file(s)
  rm -rf /tmp/pkg-dependencies-work*
  exit 1
}
Recurse() {
  pkgroot=$1
  if [ "$2" = "" ];then
    lvl=0 #-- recursion level
    pid=$$ #-- pid of top level parent process
  else
    lvl=$2
    pid=$3
  fi
  workf=/tmp/pkg-dependencies-work.$pid
  if [ $lvl -eq 0 ]; then
    #-- create work file
    rm -rf $workf
    touch $workf
  elif [ ! -f $workf ]; then
    exit 1 #-- program interrupt must have occurred and deleted the work file
  fi
  #-- generate list of dependent packages using pkg info command
  list=$(pkg info -d $pkgroot)
  n=0
  for pkg in $list; do
    n=$(($n+1)) #-- sequence number in list from pkg info command
    if [ $n -eq 1 ]; then #-- this is package name arg followed by a ":" char
      #-- display the top level package name followed by ":"
      if [ $lvl -eq 0 ]; then echo 'Package dependencies for '$pkg; fi
    else
      #-- for sub-packages, display package name after a "tab line" of "." chars
      tab=
      x=$(($lvl+1)) #-- display one "." for level 0, 2 for level 1, etc.
      while [ $x -gt 0 ]; do
        tab=$tab"."
        x=$(($x-1))
      done
      #-- check work file to learn if package name has already been displayed
      grepout=$(grep $pkg $workf)
      echo $pkg >>$workf #-- add package name to work file
      if [ "$grepout" = "" ]; then #-- package has not been displayed so do it
        echo $tab $pkg #-- display tab line and package name
        $0 $pkg $(($lvl+1)) $pid #-- invoke recursion to show sub-dependencies
      fi
    fi
  done
  if [ $lvl -eq 0 ]; then
    rm -f $workf
  fi
}

Syntax() {
  echo
  if [ "$mes" != "" ]; then
    echo "Error:  *** "$mes" ***"
    echo
  fi
  echo "Syntax: pkg-dependencies packageName"
  echo
  exit 1
}

mes=
if [ "$1" = "" ];then Syntax; fi
Recurse $*
exit 0
```


----------



## olli@ (Jan 19, 2019)

While we're at it ... This is my version of a script that displays package dependencies recursively. It doesn't use any temporary files.

```
#!/bin/sh -
#
#   This script calls "pkg info" repeatedly in order to generate
#   recursive lists of dependecies (-d) or required-by (-r).
#

set -Cefu
ME="${0##*/}"

DEBUG=false
#DEBUG=true

if $DEBUG; then
        echo "#### $ME $*" >&2
fi

Usage()
{
        echo "Usage:  $ME {-d | -r} <package> [...]" >&2
        exit 1
}

if [ $# -lt 2 ] || [ "x$1" != x-d -a "x$1" != x-r ]; then
        Usage
fi

FLAG="$1"
shift

ARGS="$*"
LIST="%"

while :; do
        if $DEBUG; then
                echo "==== pkg info -q $FLAG $ARGS" >&2
        fi
        PKGS="$(pkg info -q $FLAG $ARGS)" || {
                echo "WARNING: Exit code from pkg: $?" >&2
        }
        if $DEBUG; then
                if [ -z "$PKGS" ]; then
                        echo "---- No output." >&2
                else
                        echo "---- Output:" >&2
                        echo "----" $PKGS >&2
                fi
        fi
        if [ -z "$PKGS" ]; then
                break
        fi
        NEW_ARGS=""
        for P in $PKGS; do
                case "$LIST" in
                        *"%${P}%"*)
                                ;;
                        *)
                                LIST="${LIST}${P}%"
                                NEW_ARGS="$NEW_ARGS $P"
                                ;;
                esac
        done
        if [ -z "$NEW_ARGS" ]; then
                break
        fi
        ARGS="$NEW_ARGS"
done

echo -n "${LIST#%}" | tr '%' '\n'
```
The script is called with either `-d` or `-r`, followed by the name of the package. The meaning of the two options is the same as for `pkg info`, see the pkg-info(8) manual page.


----------



## Sensucht94 (Mar 11, 2019)

Simple screencast ksh script to record audio/video on FreeBSD using ffmpeg with OSS backend, 60fps, automatic display size adjustment, progressive naming


```
#!/usr/bin/env mksh

today="$( date +"%Y%m%d" )"
number=0

while [[ -f $HOME/Video/record_$today$count.mkv ]]
do
    (( ++number ))
    count="$( printf -- '-%02d' "$number" )"
done
fname="$HOME/Video/record_$today$count.mkv"

ffmpeg -y \
    -thread_queue_size 1024 \
    -f oss -i /dev/dsp4 -ac 2 \
    -f x11grab -r 60 \
    -s $(xdpyinfo | grep dimensions | awk '{print $2;}') \
    -i :0.0 -c:v libx264rgb -crf 0 -preset ultrafast -c:a flac \
$fname
```


----------



## aragats (Mar 11, 2019)

Sensucht94 said:


> Simple screencast ksh script to record audio/video on FreeBSD using ffmpeg


Just a note: multimedia/ffmpeg hast to be compiled with _x11grab_ support, I believe the regular package is not.


----------



## olli@ (Mar 11, 2019)

Sensucht94 said:


> Simple screencast ksh script to record audio/video on FreeBSD using ffmpeg with OSS backend, 60fps, automatic display size adjustment, progressive naming


Just a small note: With a few simple changes, the script would run with FreeBSD's /bin/sh, so people don't have to install an additional shell.

Replace `#!/usr/bin/env mksh` with `#!/bin/sh`
In the “while” line, replace the double brackets with single brackets: `[[ ... ]]` → `[ ... ]`
Replace `(( ++number ))` with `: $(( number += 1 ))` (note the colon at the beginning!)
Alternatively, I think the script would also run unchanged with bash (except for the “shebang line” at the beginning, of course), which probably most people have installed anyway.


----------



## aragats (Mar 11, 2019)

In most cases (especially with multi-monitor setup) you want to record only a part of the screen.
Below I added xinput command to get the recording area.
I used left-click for the top-left and right-click for the bottom-right corners. You can use only left-clicks, but will have to uncomment `sleep 1` to filter out bouncing.
Also, you'll need to get your pointer device ID (mouse=_*x*_) by running `xinput --list`.
For sake of simlicity I used xinput output directly as bash arrays (it should work in some other shells too), for simple sh you'll have to parse it. (I have to use bash anyway).

```
#!/usr/bin/env bash

mouse=6         # get this ID from "xinput --list"
audio=/dev/dsp5
today=$(date +"%Y%m%d")
fname_prefix="/tmp/screen_"
number=0

echo Select top left corner by clicking button 1
while true ; do
    #sleep 1
    eval `xinput --query-state $mouse | grep 'button\|valuator'`
    if [ "down" = "${button[1]}" ] ; then
        X0=${valuator[0]}
        Y0=${valuator[1]}
        break
    fi
done
echo Got: X0=$X0 Y0=$Y0

echo Select bottom right corner by clicking button 3
while true ; do
    #sleep 1
    eval `xinput --query-state $mouse | grep 'button\|valuator'`
    if [ "down" = "${button[3]}" ] ; then
        X1=${valuator[0]}
        Y1=${valuator[1]}
        break
    fi
done
echo Got: X1=$X1 Y1=$Y1

X=$((X1-X0))
Y=$((Y1-Y0))
if [ $X -le 0 ] || [ $Y -le 0 ] ; then
    echo You got negative dimensions: ${X}x${Y}
    exit 1
fi
echo Video size: ${X}x${Y}

while [ -f $fname_prefix$today$count.mkv ]
do
    $((number+=1))
    count=$(printf -- '-%02d' $number)
done
fname="$fname_prefix$today$count.mkv"

ffmpeg -y \
    -thread_queue_size 1024 \
    -f oss -i $audio -ac 2 \
    -f x11grab -r 60 \
    -s ${X}x${Y} \
    -i :0.0+$X0,$Y0 -c:v libx264rgb -crf 0 -preset ultrafast -c:a flac \
    $fname

echo $fname
```


----------



## Sensucht94 (Mar 12, 2019)

olli@ said:


> Just a small note: With a few simple changes, the script would run with FreeBSD's /bin/sh, so people don't have to install an additional shell.
> 
> Replace `#!/usr/bin/env mksh` with `#!/bin/sh`
> In the “while” line, replace the double brackets with single brackets: `[[ ... ]]` → `[ ... ]`
> ...



As I've always used ksh as interactive shell, I tend to script on it too (nver used bash or alikes), but I was definitely considering learning sh(1),...thank you for your clarifications, that's good starting point


----------



## Sensucht94 (Mar 12, 2019)

This is a simple flac2mp3 solution to convert songs recursively in a dir form lossless to mp3 encoding:


```
#!/bin/sh

for song in *.flac;
  do title=`echo "${song%.*}"`;
  echo $title;
  ffmpeg -i "$song" "${title}.mp3";
done
```

While this saves XA_CLIPBOARD content to a dotfile, using xclip(1)

```
#!/bin/sh

xclip -o | xclip -sel clip
echo $(xclip -o -sel clip) >> ~/.clipboard
gsed -n '/^\s*$/d; G; s/\n/&&/; /^\([ -~]*\n\).*\n\1/d; s/\n//; h; P' -i ~/.clipboard

notify-send "'$(xclip -o -sel clip)' saved." &
```


----------



## Eric A. Borisch (Mar 12, 2019)

Here's my script for showing differences in versions between ZFS snapshots for a particular path: https://github.com/eborisch/zfs_versions

I use the --idiff mode on /etc/rc.conf, for example, to see the evolution over time of the file.


----------



## Maxnix (Mar 12, 2019)

Sensucht94 , you don't need to use echo to assign the song name to the title variable. Just assign like this:

```
title="${song%.*}"
```
The shell will perform the substitution for you.


----------



## mrclksr (Mar 27, 2019)

Batch-encode all *.wav files in a given directory. Use each wav-file's metadata to create the ID3 tags of the corresponding mp3-file.

```
#!/bin/sh

preset="standard"
title_arg="--tt"
album_arg="--tl"
artist_arg="--ta"
date_arg="--ty"
genre_arg="--tg"
track_arg="--tn"
comment_arg="--tc"

usage() {
    echo "Usage: $(basename $0) [-p medium|standard|extreme|insane] dir"
    exit 1
}

while [ $# -gt 0 ]; do
    case "$1" in
    -p)
        preset=$2
        case "$2" in
        medium|standard|extreme|insane)
            preset=$2
            ;;
        *)
            usage
            ;;
        esac
        shift
        ;;
    -*)
        usage
        ;;
    *)
        break
        ;;
    esac
    shift
done

[ $# -lt 1  ] && usage

for cmd in ffprobe lame; do
    if ! which -s $cmd; then
        echo "$cmd not installed"
        exit 1
    fi
done
cd "$1" || exit 1
ls *.wav | while read i; do
    md=$(ffprobe -i "$i" 2>&1);
    args=""
    for k in title album artist genre track date comment; do
        val=$(echo "$md" | awk -v key=$k '{
                regx = sprintf("^[ \t]+%s[ \t]+: ", key);
                n = split($0, a, regx);
                if (n > 1) print a[2];
            }'
        )
        eval $k="\$val"
        eval arg=\${${k}_arg}
        [ -n "$val" ] && args="$args $arg \"$val\""
    done
    eval lame --preset $preset $args \"$i\" \"${i%wav}mp3\"
done
```


----------



## D-FENS (Mar 27, 2019)

This converts anything to .mp3 (depends on ffmpeg, and also mp3 encoding needs to be enabled when installing the port):

```
% cat `which convertall2mp3 `
#!/bin/bash

find . -name "*.mp4" -exec convert2mp3 -i "{}" -o "{}.mp3" \;
find . -name "*.flv" -exec convert2mp3 -i "{}" -o "{}.mp3" \;
find . -name "*.wmv" -exec convert2mp3 -i "{}" -o "{}.mp3" \;

% cat `which convert2mp3 `   
#!/bin/bash

inputfile="";
outputfile="";
quality="192k";

starttime="";
duration="";

while [ "$1" != "" ]; do

  case $1 in
      "-i" )
          shift;
          inputfile=$1;
          shift;
          ;;
      "-o" )
          shift;
          outputfile=$1;
          shift;
          ;;
      "-q" )
          shift;
          quality=$1;
          shift;
          ;;
      "-ss" )
          shift;
          starttime="-ss $1";
          shift;
          ;;
      "-t" )
          shift;
          duration="-t $1";
          shift;
          ;;
      * )
          echo WARNING: Unknown parameter $1;
          shift;
          ;;
  esac;

done;

if [ "$inputfile" == "" ] || [ "$outputfile" == "" ]; then
  echo Usage: convert2mp3 -i inputfile -o outputfile [-q quality] [-ss starttime] [-t duration];
  echo ...... quality = 128k 160k 96k etc.;
  echo        ss = hh:mm:ss
  echo        t  = hh:mm:ss

else

  echo "Input file: $inputfile";
  echo "Output file: $outputfile";
  echo "Quality: $quality";

#  avconv -i "$inputfile" -acodec libmp3lame -ab $quality -ac 2 -ar 44100 "$outputfile";

  echo ffmpeg $starttime $duration -i "$inputfile" -b:a $quality -vn "$outputfile";
       ffmpeg $starttime $duration -i "$inputfile" -b:a $quality -vn "$outputfile";

fi;
```


----------



## NuLL3rr0r (May 8, 2019)

My Bash Script to Brighten up your FreeBSD box by wallpapers from Reddit

Documentation and more information https://www.babaei.net/blog/my-reddit-wallpaper-downloader-script/


```
#!/usr/bin/env bash

#  (The MIT License)
#
#  Copyright (c) 2018 - 2019 Mamadou Babaei
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.


set +e

readonly FMT_OFF='\e[0m'
readonly FMT_INFO='\e[1;32m'
readonly FMT_WARN='\e[1;33m'
readonly FMT_ERR='\e[1;91m'
readonly FMT_FATAL='\e[1;31m'

readonly LOG_INFO="INFO"
readonly LOG_WARN="WARNING"
readonly LOG_ERR="ERROR"
readonly LOG_FATAL="FATAL"

readonly E_TRUE="true"
readonly E_FALSE="false"

readonly BASENAME="basename"
readonly CALLER="caller"
readonly CUT=$(which cut 2>/dev/null)
readonly CURL=$(which curl 2>/dev/null)
readonly DATE=$(which date 2>/dev/null)
readonly ECHO="echo"
readonly ECHO_FMT="echo -e"
readonly ESETROOT=$(which esetroot 2>/dev/null)
readonly FEH=$(which feh 2>/dev/null)
readonly FIREFOX=$(which firefox 2>/dev/null)
readonly HSETROOT=$(which hsetroot 2>/dev/null)
readonly JQ=$(which jq 2>/dev/null)
readonly LOGGER="logger"
readonly PERL=$(which perl 2>/dev/null)
readonly PRINT="print"
readonly REV=$(which rev 2>/dev/null)
readonly TR=$(which tr 2>/dev/null)
readonly XSETROOT=$(which xsetroot 2>/dev/null)

if [[ -n "${ESETROOT}" ]] ;
then
    readonly SETROOT=${ESETROOT}
elif [[ -n "${HSETROOT}" ]] ;
then
    readonly SETROOT=${HSETROOT}
elif [[ -n "${XSETROOT}" ]] ;
then
    readonly SETROOT=${XSETROOT}
fi

readonly SCRIPT="${BASH_SOURCE[0]}"
readonly SCRIPT_NAME="$(${BASENAME} -- "${SCRIPT}")"
readonly SYSLOG_TAG="$(${BASENAME} -- "${SCRIPT}" | ${TR} '[:lower:]' '[:upper:]' | ${REV} | ${CUT} -d "." -f2- | ${REV})"

readonly SUBREDDIT_CATEGORY_ANIMALS="AnimalsBeingBros+AnimalsBeingDerps+AnimalsBeingJerks+aww+Eyebleach+likeus+rarepuppers"
readonly SUBREDDIT_CATEGORY_ART="Art+ArtPorn+Cinemagraphs+ExposurePorn+Graffiti+ImaginaryLandscapes+itookapicture"
readonly SUBREDDIT_CATEGORY_FOOD="Breadit+eatsandwiches+food+FoodPorn+grilledcheese+Pizza+slowcooking"
readonly SUBREDDIT_CATEGORY_IMAGINARY="ImaginaryBehemoths+ImaginaryCharacters+ImaginaryLandscapes+ImaginaryLeviathans+ImaginaryMindscapes+ImaginaryMonsters+ImaginaryTechnology"
readonly SUBREDDIT_CATEGORY_MAN_MADE="AbandonedPorn+carporn+CityPorn+CozyPlaces+DesignPorn+powerwashingporn+RoomPorn"
readonly SUBREDDIT_CATEGORY_NATURE="chemicalreactiongifs+EarthPorn+MacroPorn+physicsgifs+spaceporn+waterporn+WeatherGifs"

readonly DEFAULT_SUBREDDIT="r/${SUBREDDIT_CATEGORY_ART}+${SUBREDDIT_CATEGORY_IMAGINARY}"
readonly DEFAULT_SORT_BY="hot"
readonly DEFAULT_IS_NSFW_OK="${E_FALSE}"
readonly DEFAULT_BACKGROUND_COLOR="282828"
readonly DEFAULT_FEH_ARGS="--no-fehbg --image-bg black --bg-max"

readonly DEFAULT_FIREFOX_VERSION_STRING="Mozilla Firefox 66.0"

readonly LOCAL_WALLPAPER_DIR="${HOME}/.cache/reddit_wallpapers/"
readonly LOCAL_WALLPAPER_NAME="$(${DATE} +%Y-%m-%d-%H-%M-%S)"

function usage() {
    readonly local message="${1}"

    ${ECHO}

    if [[ -n "${message}" ]] ;
    then
        err "${message}${FMT_OFF}"
        ${ECHO}
    fi

    ${ECHO_FMT} "${FMT_INFO}Correct usage:${FMT_OFF}"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}${SCRIPT_NAME} -h | [-r {r/subreddit}] [-s {sorty by}] [-n] [-b {background color}] [-f 'feh args']${FMT_OFF}"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}-h: shows this usage note"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}-r: subreddit name or names prefixed with r/ and combined by a + sign (e.g. r/Art or r/Art+ArtPorn; default: ${DEFAULT_SUBREDDIT})${FMT_OFF}"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}-s: reddit sort algorithm (e.g. hot, new, controversial, top, rising; default: ${DEFAULT_SORT_BY})${FMT_OFF}"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}-n: allow nsfw wallpapers (no nsfw wallpaper is allowed by default, unless this flag is passed)${FMT_OFF}"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}-b: hex rgb color in 'ffffff' format (default: ${DEFAULT_BACKGROUND_COLOR})${FMT_OFF}"
    ${ECHO}
    ${ECHO_FMT} "    ${FMT_INFO}-f: feh arguments to pass; run 'man feh' for a list of available options (default: ${DEFAULT_FEH_ARGS})${FMT_OFF}"
    ${ECHO}

    if [[ -n "${message}" ]] ;
    then
        exit 1
    else
        exit 0
    fi
}

function log()
{
    local log_type=$1; shift
    local line=$1; shift
    local fmt=$1; shift

    if [[ -n "$1" && -n "$@" ]] ;
    then
        ${ECHO_FMT} "${fmt}[${log_type}] ${line} $@${FMT_OFF}"
        ${LOGGER} -t "${SYSLOG_TAG}" "${log_type} ${line} $@"
    else
        ${ECHO_FMT} "${FMT_WARN}[${LOG_WARN}] ${line} A null log detected!${FMT_OFF}"
        ${LOGGER} -t "${SYSLOG_TAG}" "${LOG_WARN} ${line} A null log detected!"
    fi 
}

function info()
{
    local line=$( "${ECHO}" $( "${CALLER}" 0 ) | "${CUT}" -d " " -f1 )

    log "${LOG_INFO}" "${line}" "$FMT_INFO" "$@"
}

function warn()
{
    local line=$( "${ECHO}" $( "${CALLER}" 0 ) | "${CUT}" -d " " -f1 )

    log "${LOG_WARN}" "${line}" "${FMT_WARN}" "$@"
}

function err()
{
    local line=$( "${ECHO}" $( "${CALLER}" 0 ) | "${CUT}" -d " " -f1 )

    log "${LOG_ERR}" "${line}" "${FMT_ERR}" "$@"
}

function fatal()
{
    local line=$( "${ECHO}" $( "${CALLER}" 0 ) | "${CUT}" -d " " -f1 )

    log "${LOG_FATAL}" "${line}" "${FMT_FATAL}" "$@"

    exit 1
}

if [[ -z "${CUT}" ]] ;
then
    fatal "Could not find command cut!"
fi

if [[ -z "${CURL}" ]] ;
then
    fatal "Could not find command curl!"
fi

if [[ -z "${DATE}" ]] ;
then
    fatal "Could not find command date!"
fi

if [[ -z "${FEH}" ]] ;
then
    fatal "Could not find command feh!"
fi

if [[ -z "${JQ}" ]] ;
then
    fatal "Could not find command jq!"
fi

if [[ -z "${PERL}" ]] ;
then
    fatal "Could not find command perl!"
fi

if [[ -z "${REV}" ]] ;
then
    fatal "Could not find command rev!"
fi

if [[ -z "${SETROOT}" ]] ;
then
    fatal "Could not find any setroot command!"
fi

if [[ -z "${TR}" ]] ;
then
    fatal "Could not find command tr!"
fi

while getopts ":h :r: :s: :n :b: :f:" ARG;
do
    case ${ARG} in
        h)
            usage
            ;;
        r)
            SUBREDDIT=${OPTARG}
            ;;
        s)
            SORT_BY=${OPTARG}
            ;;
        n)
            IS_NSFW_OK="${E_TRUE}"
            ;;
        b)
            BACKGROUND_COLOR="#${OPTARG}"
            ;;
        f)
            FEH_ARGS="${OPTARG}"
            ;;
        \?)
            usage "Invalid option: '-${OPTARG}'!"
        ;;
    esac
done

if [[ -z ${SUBREDDIT} ]] ;
then
    SUBREDDIT=${DEFAULT_SUBREDDIT}
fi

readonly SUBREDDIT_REGEX="^r\/([a-zA-Z0-9_+]+)$"

if [[ ! "${SUBREDDIT}" =~ ${SUBREDDIT_REGEX} ]] ;
then
    fatal "Invalid subreddit name! use r/subreddit or r/subreddit1+subreddit2 format!"
fi

if [[ -z ${SORT_BY} ]] ;
then
    SORT_BY=${DEFAULT_SORT_BY}
fi

if [[ "${SORT_BY}" != "hot"
        && "${SORT_BY}" != "new"
        && "${SORT_BY}" != "controversial"
        && "${SORT_BY}" != "top"
        && "${SORT_BY}" != "rising" ]] ;
then
    fatal "Invalid reddit sort algorithm!"
fi

if [[ -z ${IS_NSFW_OK} ]] ;
then
    NSFW_OK=${DEFAULT_IS_NSFW_OK}
fi

if [[ -z ${BACKGROUND_COLOR} ]] ;
then
    BACKGROUND_COLOR="#${DEFAULT_BACKGROUND_COLOR}"
fi

readonly BACKGROUND_COLOR_REGEX="^#([0-9a-f]{6})$"

if [[ ! "${BACKGROUND_COLOR}" =~ ${BACKGROUND_COLOR_REGEX} ]] ;
then
    fatal "Invalid background color format! the only accepted format is 'ffffff'!"
fi

if [[ -z ${FEH_ARGS} ]] ;
then
    FEH_ARGS=${DEFAULT_FEH_ARGS}
fi

if [[ -z "${FIREFOX}" ]] ;
then
    warn "Firefox executable not found!"
    readonly FIREFOX_VERSION_STRING="${DEFAULT_FIREFOX_VERSION_STRING}"
    warn "Setting Firefox version string to: ${FIREFOX_VERSION_STRING}"
else
    readonly FIREFOX_VERSION_STRING=$(${FIREFOX} -version)
fi

readonly FIREFOX_VERSION_NUMBER=$(${ECHO} "${FIREFOX_VERSION_STRING}" | ${PERL} -nle "m/[-+]?([0-9]*\.[0-9]+|[0-9]+)/; ${PRINT} \$1")
readonly FIREFOX_USER_AGENET="Mozilla/5.0 (X11; Linux x86_64; rv:${FIREFOX_VERSION_NUMBER}) Gecko/20100101 Firefox/${FIREFOX_VERSION_NUMBER}"

info "Run '${SCRIPT_NAME} -h' for more information on available options."

info "Setting user agent to '${FIREFOX_USER_AGENET}'..."

readonly JSON_URL="https://www.reddit.com/${SUBREDDIT}/${SORT_BY}.json"

info "Downloading meta file '${JSON_URL}'..."

readonly JSON_CONTENT=$(${CURL} -A "${FIREFOX_USER_AGENET}" -sSL ${JSON_URL})
RC=$?

if [[ $RC -ne 0 ]] ;
then
    fatal "Subreddit meta file download has failed!"
fi

readarray JSON_POSTS <<< "$(${ECHO} "${JSON_CONTENT}" | ${JQ} --compact-output '.data.children[]')"
RCS=(${PIPESTATUS[*]})

if [[ ${RCS[0]} -ne 0 || ${RCS[1]} -ne 0 ]] ;
then
    fatal "Failed to parse the subreddit's meta file!"
fi

readonly URL_REGEX="^(https?://)?(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-z_!~*'()-]+\\.)*([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\.[a-z]{2,6})(:[0-9]{1,4})?((/?)|(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)\\.(png|apng|jpg|jpeg|jpe|jif|jfif|jfi|gif|tiff|tif)$"

FOUND_A_SUITABLE_WALLPAPER="${E_FALSE}"

for post in "${JSON_POSTS[@]}" ;
do
    if [[ "${IS_NSFW_OK}" != "${E_TRUE}" ]] ;
    then
        IS_OVER_18_POST=$(${ECHO} "${post}" | ${JQ} --compact-output '.data.over_18')
        RCS=(${PIPESTATUS[*]})

        if [[ ${RCS[0]} -ne 0 || ${RCS[1]} -ne 0 ]] ;
        then
            fatal "Failed to parse the subreddit's meta file!"
        fi

        if [[ "${IS_OVER_18_POST}" == "${E_TRUE}" ]] ;
        then
            continue
        fi
    fi

    WALLPAPER_URL=$(${ECHO} "${post}" | ${JQ} --raw-output '.data.url')
    RCS=(${PIPESTATUS[*]})

    if [[ ${RCS[0]} -ne 0 || ${RCS[1]} -ne 0 ]] ;
    then
        fatal "Failed to parse the subreddit's meta file!"
    fi

    if [[ ! "${WALLPAPER_URL}" =~ ${URL_REGEX} ]] ;
    then
        continue
    fi

    WALLPAPER_EXTENSION="${WALLPAPER_URL##*.}"

    if [[ -z "${WALLPAPER_EXTENSION}" ]] ;
    then
        continue
    fi

    FOUND_A_SUITABLE_WALLPAPER="${E_TRUE}"
    break;
done

if [[ "${FOUND_A_SUITABLE_WALLPAPER}" != "${E_TRUE}" ]] ;
then
    fatal "Could not find a suitable wallpaper on '${SUBREDDIT}'!"
fi

readonly LOCAL_WALLPAPER_PATH="${LOCAL_WALLPAPER_DIR}/${LOCAL_WALLPAPER_NAME}.${WALLPAPER_EXTENSION}"

info "Found a wallpaper on '${SUBREDDIT}' at '${WALLPAPER_URL}'!"
info "Fetching '${WALLPAPER_URL}'..."

${CURL} -fLo "${LOCAL_WALLPAPER_PATH}" --create-dirs ${WALLPAPER_URL} > /dev/null 2>&1
RC=$?

if [[ $RC -ne 0 ]] ;
then
    fatal "Failed to fetch the wallpaper file from '${WALLPAPER_URL}'!"
fi

info "Setting desktop background color to '${BACKGROUND_COLOR}'..."

${SETROOT} -solid "${BACKGROUND_COLOR}" > /dev/null 2>&1 &
RC=$?

if [[ $RC -ne 0 ]] ;
then
    fatal "Failed to set the background color to '${BACKGROUND_COLOR}'!"
fi

info "Using '${WALLPAPER_URL}' as the desktop wallpaper..."

${FEH} ${FEH_ARGS} "${LOCAL_WALLPAPER_PATH}" > /dev/null 2>&1 &
RC=$?

if [[ $RC -ne 0 ]] ;
then
    fatal "Failed to apply '${LOCAL_WALLPAPER_PATH}' as the desktop background image!"
fi

info "Done!"
info "Hope you enjoy it :)"
```


----------



## hukadan (May 9, 2019)

Here is the script I use to update my system from source using boot environment. The building world and kernel part is a copy&paste of http://www.wonkity.com/~wblock/docs/html/buildworld.html. I am still learning shell scripting and struggling with proper error handling, so critics are more than welcome.

```
# !/bin/sh

set -eu

trap cleanup 2

MNT_POINT=$(mktemp -d /tmp/sysupgrade-XXXXXX) ||
    { echo "could not create mount point" ; exit 1 ;}
REVISION=$(svn info --show-item revision /usr/src) ||
    { echo "could not get revision number" ; exit 1 ;}
RELEASE=$(uname -r) ||
    { echo "could not get release" ; exit 1 ;}
BE_NAME=${RELEASE}-${REVISION}
JOB_NUMBER=7

create_be(){
    echo "==> creating boot environment"
    bectl create ${BE_NAME} ||
        { echo "could not create boot environment" ; exit 1 ;}
}

mount_be(){
    echo "==> mounting boot environment"
    bectl mount ${BE_NAME} ${MNT_POINT} ||
        { echo "could not mount boot environment" ; exit 1 ;}
    mount -t devfs devfs ${MNT_POINT}/dev ||
        { echo "could not mount devfs" ; exit 1 ;}
    mount_nullfs /usr/src ${MNT_POINT}/usr/src ||
        { echo "could not mount /usr/src" ; exit 1 ;}
}

umount_be(){
    echo "==> umounting boot environment"
    umount ${MNT_POINT}/dev ||
        { echo "could not umount devfs" ; exit 1 ;}
    umount ${MNT_POINT}/usr/src ||
        { echo "could not umount /usr/src" ; exit 1 ;}
    bectl umount ${BE_NAME} ||
        { echo "could not umount boot environment" ; exit 1 ;}
    rmdir ${MNT_POINT} ||
        { echo "could not delete mount point" ; exit 1 ;}
}

destroy_be(){
    echo "==> destroying boot environment"
    bectl destroy -o ${BE_NAME} ||
       { echo "could not destroy boot environment" ; exit 1 ;}
}

create_script(){
    cat << EOT > ${MNT_POINT}/script.sh
# !/bin/sh

echo "removing /usr/obj... this may take a while"
rm -rf /usr/obj ||
        { echo "coud not remove /usr/obj" ; exit 1 ;}
cd /usr/src ||
        { echo "couldn't reach /usr/src" ; exit 1 ;}
echo "building world"
make -j${JOB_NUMBER} buildworld ||
        { echo "buildworld failed" ; exit 1 ;}
echo "building and installing kernel"
make -j${JOB_NUMBER} kernel ||
        { echo "kernel failed" ; exit 1 ;}
echo "intalling world"
make installworld ||
        { echo "installworld failed" ; exit 1 ;}
echo "merging files"
mergemaster -Ui
echo "checking old"
make check-old
echo "deleting old"
make delete-old
echo "delete old libs"
make delete-old-libs
echo "removing install script"
rm /script.sh ||
        { echo "install script could not be removed" ; exit 1 ;}
EOT
    return 0
}

chroot_exec(){
    echo "==> chrooting"
    chroot ${MNT_POINT} /bin/sh script.sh
}

cleanup(){
    echo "==> cleaning"
    umount_be
    destroy_be
}

upgrade(){
    create_be
    mount_be
    create_script
    chroot_exec
    umount_be
}

upgrade
```


----------



## NuLL3rr0r (May 10, 2019)

My script for keeping the crashing daemons running.

A blog post explaining it.


```
#!/usr/bin/env sh

#  (The MIT License)
#
#  Copyright (c) 2019 Mamadou Babaei
#
#  Permission is hereby granted, free of charge, to any person obtaining a copy
#  of this software and associated documentation files (the "Software"), to deal
#  in the Software without restriction, including without limitation the rights
#  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the Software is
#  furnished to do so, subject to the following conditions:
#
#  The above copyright notice and this permission notice shall be included in
#  all copies or substantial portions of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#  THE SOFTWARE.


set +e

readonly BASENAME="basename"
readonly CUT="/usr/bin/cut"
readonly ECHO="echo -e"
readonly GREP="/usr/bin/grep"
readonly LOGGER="/usr/bin/logger"
readonly PS="/bin/ps"
readonly REV="/usr/bin/rev"
readonly TR="/usr/bin/tr"

readonly FMT_OFF='\e[0m'
readonly FMT_INFO='\e[1;32m'
readonly FMT_WARN='\e[1;33m'
readonly FMT_ERR='\e[1;91m'
readonly FMT_FATAL='\e[1;31m'

readonly LOG_INFO="INFO"
readonly LOG_WARN="WARNING"
readonly LOG_ERR="ERROR"
readonly LOG_FATAL="FATAL"

readonly SCRIPT="$0"
readonly SCRIPT_NAME="$(${BASENAME} -- "${SCRIPT}")"
readonly SYSLOG_TAG="$(${BASENAME} -- "${SCRIPT}" \
    | ${TR} '[:lower:]' '[:upper:]' \
    | ${REV} \
    | ${CUT} -d "." -f2- \
    | ${REV})"

usage()
{
    ${ECHO}
    ${ECHO} "${FMT_INFO}Correct usage:${FMT_OFF}"
    ${ECHO}
    ${ECHO} "    ${FMT_INFO}${SCRIPT_NAME} -e {executable full path} -s {service name to (re)start} [-s {another service name to (re)start}] [... even more -s and service names to (re)start]${FMT_OFF}"
    ${ECHO}

    exit 1
}

log()
{
    log_type=$1; shift
    fmt=$1; shift

    if [ -n "$1" -a -n "$@" ] ;
    then
        ${ECHO} "${fmt}[${log_type}] $@${FMT_OFF}"
        ${LOGGER} -t "${SYSLOG_TAG}" "${log_type} $@"
    fi 
}

info()
{
    log "${LOG_INFO}" "${FMT_INFO}" "$@"
}

warn()
{
    log "${LOG_WARN}" "${FMT_WARN}" "$@"
}

err()
{
    log "${LOG_ERR}" "${FMT_ERR}" "$@"
}

fatal()
{
    log "${LOG_FATAL}" "${FMT_FATAL}" "$@"
    exit 1
}

restart_service()
{
    service_name="$1"

    info "Stopping the service '${service_name}'..."
    service ${service_name} stop > /dev/null 2>&1

    if [ "$?" -eq 0 ] ;
    then
        info "The '${service_name}' service has been stopped successfully!"
    else
        err "Failed to stop the '${service_name}' service!"
    fi

    info "Starting the service '${service_name}'..."
    service ${service_name} start > /dev/null 2>&1

    if [ "$?" -eq 0 ] ;
    then
        info "The '${service_name}' service has been started successfully!"
    else
        err "Failed to start the '${service_name}' service!"
    fi
}

if [ "$#" -eq 0 ] ;
then
    usage
fi

SERVICE_COUNT=0

while getopts ":e: :s:" ARG ;
do
    case ${ARG} in
        e)
            if [ -z "${OPTARG}" ] ;
            then
                err "Missing executable ${OPTARG}!"
                usage
            fi

            if [ ! -f "${OPTARG}" ] ;
            then
                fatal "The executable '${OPTARG}' does not exist!"
            fi

            readonly DAEMON="${OPTARG}"
            ;;
        s)
            if [ ! -f "/usr/etc/rc.d/${OPTARG}" \
                -a ! -f "/usr/local/etc/rc.d/${OPTARG}" ] ;
            then
                fatal "No such a service exists: '${OPTARG}'!"
            fi

            SERVICE_COUNT=$((SERVICE_COUNT+1))
            ;;
        \?)
            err "Invalid option: -${OPTARG}!"
            usage
        ;;
    esac
done

if [ "${SERVICE_COUNT}" -eq 0 ] ;
then
    err "At least one service name is required!"
    usage
fi

readonly DAEMON_PROCESS_COUNT=$(${PS} aux \
    | ${GREP} -v "${GREP}" \
    | ${GREP} -v "${SCRIPT}" \
    | ${GREP} -c "${DAEMON}")

if [ "${DAEMON_PROCESS_COUNT}" -lt 1 ] ;
then
    warn "'${DAEMON}' is not running!"

    OPTIND=1
    while getopts ":e: :s:" ARG ;
    do
        case ${ARG} in
            s)
                restart_service "${OPTARG}"
                ;;
            \?)
            ;;
        esac
    done
else
    info "'${DAEMON}' is running!"
    info "No action is required!"
fi
```


----------



## kpedersen (May 31, 2019)

I was on the train to Glasgow the other day; I brought my old Thinkpad T23 running MS-DOS to play some DOS games for entertainment. I decided to do a bit of coding but remembered that CMake has not been ported to DOS (yet?). So decided to make a new build system using a tool that is present on every development machine I use... Vim!

Save it in a file (i.e iffe.vim) You can either make it executable and run it, or you can run it with `vim -S iffe.vim`

Some features:

Pure 100% unadulterated VimScript
Fast! (due to lack of features )
Dependency checking (including recursive header searching)
Logic does not use recursion so it can work on... DOS! (open / closed list similar to A* used instead)
It requires no build file, instead it works out based on the filesystem structure how the project should be built. i.e


```
projname/ <--- you are here
  iffe.vim
  src/
    somelib/
      Test.cpp
      Test.h
    somebin/
      main.cpp
```

This will then generate a bunch of .o files in the obj folder, a libsomelib.a static library in the lib folder and somebin executable in the bin folder. It will also store the dependencies database in obj/dependencies.iffe for subsequent builds.

Unfortunately the trip was over before I managed to do any actual coding XD


```
#!/usr/local/bin/vim -S

" BSD / LLVM
let s:compiler = "clang++"
let s:objSuffix = "o"
let s:exeSuffix = ""

" DOS / DJGPP
"let s:compiler = "g++"
"let s:objSuffix = "o"
"let s:exeSuffix = "exe"

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Output
"
" Write the specified message to the buffer using normal mode and then request
" a redraw to ensure that the text is visible even if further processing is
" needing to be done.
"
" message - The message to add to the buffer
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function Output(message)

  execute("normal! Ga" . a:message . "\n")
  redraw!

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" FileCreate
"
" Based on the specified path, populate a structure for the relevent file.
" The data to be populated includes information on whether it is a header or
" source unit. If a source unit, then generate a path to be used for the
" compiled object. If the file is called "main" then set the executable flag
" in the parent project so it is known to not just be a library.
"
" project - The parent project of this file
" path - The relative file path
"
" Returns - The populated file structure
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function FileCreate(project, path)

  let l:ctx = {}
  let l:ctx.project = a:project
  let l:ctx.path = a:path
  let l:ctx.name = fnamemodify(l:ctx.path, ':t')
  let l:ctx.absolutepath = fnamemodify(l:ctx.path, ':p')
  let l:ctx.timestamp = getftime(l:ctx.path)
  let l:ctx.dependencies = []

  if fnamemodify(l:ctx.path, ':e') == "cpp"
    let l:ctx.objpath = fnamemodify(l:ctx.path, ':t:r')

    if l:ctx.objpath == "main"
      let a:project.executable = 1
    endif

    let l:objpath = "obj/" . l:ctx.project.name . "/"
    let l:objpath = l:objpath . l:ctx.objpath . "." . s:objSuffix
    let l:ctx.objpath = l:objpath
  else
    let l:ctx.objpath = ""
  endif

  return l:ctx

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" DepParserCreate
"
" Create a structure containing the necessary data store for the dependency
" parser. In particular create two arrays referring to the open and closed
" list and prepopulate the open list with the initial source unit to scan.
"
" file - The file to pre-populate the open list with
"
" Returns - The created parser context
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function DepParserCreate(file)

  let ctx = {}
  let ctx.iffe = a:file.project.iffe
  let ctx.open = []
  call add(ctx.open, a:file)
  let ctx.closed = []

  return ctx

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" DepParserProcess
"
" Read the required files and generate a list of all included dependencies
" recursively. The method itself is not recursive (to reduce the required
" stack size on weaker platforms such as DOS) and as such uses an open / closed
" list system (in a similar way to path finding). By the end of the process the
" closed list within the context will contain the initial files and all of
" their dependencies.
"
" ctx - The parser context
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function DepParserProcess(ctx)

  while len(a:ctx.open) > 0
    let l:file = a:ctx.open[0]
    call remove(a:ctx.open, 0)
    call add(a:ctx.closed, l:file)

    let l:data = readfile(l:file.path)

    for l:line in l:data
      if l:line =~ "^#include"
        let l:line = substitute(l:line, '"\s*$', "", "")
        let l:line = substitute(l:line, '>\s*$', "", "")
        let l:line = substitute(l:line, '^.*"', "", "")
        let l:line = substitute(l:line, '^.*<', "", "")

        let l:inc = fnamemodify(l:line, ':t')
        let l:found = 0

        for l:ent in a:ctx.open
          if l:ent.name == l:inc
            let l:found = 1
            break
          endif
        endfor

        if l:found == 0
          for l:ent in a:ctx.closed
            if l:ent.name == l:inc
              let l:found = 1
              break
            endif
          endfor
        endif

        if l:found == 0
          for l:ent in a:ctx.iffe.headers
            if l:ent.name == l:inc
              call add(a:ctx.open, l:ent)
            endif
          endfor
        endif
      endif
    endfor

  endwhile

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" SourceUpdateDependencies
"
" Update all the dependencies of the specified source file by creating an
" instance of the file parser, adding any source file with the specified file's
" name, and processing it. All files in the closed list which are header files
" are copied into the source as dependencies (replacing the existing list).
"
" ctx - The source file to update
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function SourceUpdateDependencies(ctx)

  let l:dp = DepParserCreate(a:ctx)

  for l:src in a:ctx.project.iffe.sources
    if l:src == a:ctx
      continue
    endif

    if l:src.name == a:ctx.name
      call add(l:dp.open, l:src)
    endif
  endfor

  call DepParserProcess(l:dp)
  let a:ctx.dependencies = []

  for l:dep in l:dp.closed
    if l:dep.objpath == ""
      call add(a:ctx.dependencies, l:dep)
    endif
  endfor

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" SourceBuild
"
" Build the specified source file using its path and its generated object path.
" The "obj" folders for the files project are created if they do not exist.
" This runs the current compiler with the correct arguments. Finally update
" the dependencies of the file because we now have an up to date object but the
" included files might change in future.
"
" ctx - The source unit to compile into an object
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function SourceBuild(ctx)

  "call Output("Building: " . a:ctx.name)
  "call Output("for Project: " . a:ctx.project.name)

  if !isdirectory("obj")
    call mkdir("obj")
  endif

  if !isdirectory("obj/" . a:ctx.project.name)
    call mkdir("obj/" . a:ctx.project.name)
  endif

  let l:cmd = s:compiler . " -c -o " . a:ctx.objpath . " -Isrc " . a:ctx.path
  call Output(l:cmd)
  let l:output = system(l:cmd)

  if l:output != ""
    call Output(l:output)
  endif

  call SourceUpdateDependencies(a:ctx)

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" ProjectCreate
"
" Populate the project structure based on the details of the specified path.
" Scan the respective directory (not recursively) for any source and header
" files and add them to the correct list. Based on if any of those files were
" called "main" the executable flag will be set and generate a correct output
" filename for this project which will be used when building.
"
" iffe - The encapsulating parent system
" path - The relative path of the project
"
" Returns - The populated project structure
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function ProjectCreate(iffe, path)

  let l:ctx = {}
  let l:ctx.path = a:path
  let l:ctx.name = fnamemodify(l:ctx.path, ':t')
  let l:ctx.absolutepath = fnamemodify(l:ctx.path, ':p:h')
  let l:ctx.sources = []
  let l:ctx.headers = []
  let l:ctx.executable = 0
  let l:files = globpath(l:ctx.path, '*')
  let l:files = split(l:files, '\n')

  for l:path in l:files

    if getftype(l:path) != "file"
      continue
    endif

    let l:file = FileCreate(l:ctx, l:path)

    if l:file.objpath == ""
      call add(l:ctx.headers, l:file)
      call add(a:iffe.headers, l:file)
    else
      call add(l:ctx.sources, l:file)
      call add(a:iffe.sources, l:file)
    endif

  endfor

  let l:suff = s:exeSuffix

  if l:suff != ""
    let l:suff = "." . l:suff
  endif

  if l:ctx.executable == 1
    let l:ctx.outpath = "bin/" . l:ctx.name . l:suff
  else
    let l:ctx.outpath = "lib/lib" . l:ctx.name . ".a"
  endif

  return l:ctx

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" SourceRequiresBuild
"
" Ascertain whether the specified source unit requires a rebuild. This is done
" by checking if the timestamp of the file is more recent than the existing
" object or if any of its dependencies have a more recent timestamp.
"
" ctx - The source file to query
"
" Returns - 1 if the source requires a rebuild or 0 otherwise
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function SourceRequiresBuild(ctx)

  " TODO: Testing
  "return 1

  let l:objtimestamp = getftime(a:ctx.objpath)

  if a:ctx.timestamp > l:objtimestamp
    return 1
  endif

  for l:dep in a:ctx.dependencies
    if l:dep.timestamp > l:objtimestamp
      return 1
    endif
  endfor

  return 0

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" ProjectBuild
"
" All the sources belonging to the project are built. If any of the resulting
" objects are newer than the relevant executable or library file the project
" output is linked into an executable or archived into a library depending on
" the type. The "bin" or "lib" directory is created if it does not already
" exist.
"
" ctx - The specified project to build
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function ProjectBuild(ctx)

  "call Output("Processing: " . a:ctx.name)
  let l:objstr = ""
  let l:newest = -1

  for l:source in a:ctx.sources

    if SourceRequiresBuild(l:source)
      call SourceBuild(l:source)
    endif

    let l:objstr = l:objstr . l:source.objpath . " "
    let l:objts = getftime(l:source.objpath)

    if l:objts > l:newest
      let l:newest = l:objts
    endif

  endfor

  if getftime(a:ctx.outpath) >= l:newest
    return
  endif

  if a:ctx.executable == 1

    if !isdirectory("bin")
      call mkdir("bin")
    endif

    let l:cmd = s:compiler . " -o " . a:ctx.outpath . " " . l:objstr
    call Output(l:cmd)
    let l:output = system(l:cmd)

    if l:output != ""
      call Output(l:output)
    endif
  else
    if !isdirectory("lib")
      call mkdir("lib")
    endif

    let l:cmd = "ar rcs " . a:ctx.outpath . " " . l:objstr
    call Output(l:cmd)
    let l:output = system(l:cmd)

    if l:output != ""
      call Output(l:output)
    endif
  endif

  call Output("")

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffePopulateProjects
"
" Scan through the "src" directory for any folders. Assume that these are
" projects so process them and add them to the list.
"
" ctx - The encapsulated system
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffePopulateProjects(ctx)

  let a:ctx.projects = []
  let a:ctx.sources = []
  let a:ctx.headers = []

  let l:files = globpath("src", '*')
  let l:files = split(l:files, '\n')

  for l:file in l:files
    if getftype(l:file) != "dir"
      continue
    endif

    let l:project = ProjectCreate(a:ctx, l:file)
    let l:project.iffe = a:ctx
    call add(a:ctx.projects, l:project)
  endfor

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeRestoreDependencies
"
" If the dependencies file exists, read through it whilst matching any source
" files with a name from the file. If any files match go through the list of
" dependencies from the file and if any header files match these names, then
" add them to the source file as a dependency. As a redundant check in case
" there are duplicate entries (there should not be), create a hash of any new
" dependencies and source and add it to a list to be subsequently checked to
" ensure that a source file does not receive the same dependency twice (same
" file name is fine so long as the path is different).
"
" ctx - The encapsulated system
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeRestoreDependencies(ctx)

  let l:added = []

  if !filereadable("obj/dependencies.iffe")
    return
  endif

  let l:lines = readfile("obj/dependencies.iffe")

  for l:line in l:lines
    let l:source = substitute(l:line, ': .*$', "", "")
    let l:dstr = substitute(l:line, '.*: ', "", "")
    let l:deps = split(l:dstr, ' ')

    "call Output("Deps: " . l:source)

    "for l:dep in l:deps
    "  call Output("Dep: " . l:dep)
    "endfor

    for l:s in a:ctx.sources
      if l:s.name != l:source
        continue
      endif

      "call Output("Source: " . l:s.name)

      for l:dep in l:deps
        for l:d in a:ctx.headers
          if l:d.name == l:dep

            let l:found = 0

            for l:a in l:added
              if l:a == l:s.path . " " . l:d.path
                let l:found = 1
                break
              endif
            endfor

            if l:found == 0
              "call Output("Source: " . l:s.name . " Dep: " . l:d.path)
              call add(l:added, l:s.path . " " . l:d.path)
              call add(l:s.dependencies, l:d)
            endif

          endif
        endfor
      endfor
    endfor
  endfor

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeCreate
"
" Output a small banner, create the encapsulated system structure and populate
" it with projects.
"
" Returns - The encapsulated system structure
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeCreate()

  let l:ctx = {}

  call Output("Iffe Build System")
  call Output("-----------------")

  call IffePopulateProjects(l:ctx)
  call IffeRestoreDependencies(l:ctx)

  return l:ctx

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeStoreDependencies
"
" For all of the sources, iterate through all of their dependencies and output
" their filenames into the dependencies file. The main thing to note is that
" a source with the same name but entirely different paths will actually share
" the same dependencies (to keep things simple and not depend on paths), so it
" is only necessary to output one of them. For this reason a list is created
" to store the processed sources and only the first time a source with a given
" name is encountered is it added to the file. The dependencies file is stored
" in the "obj" folder which is created if it does not already exist.
"
" ctx - The encapsulated system
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeStoreDependencies(ctx)

  let l:lines = []
  let l:seen = []

  for l:file in a:ctx.sources
    let l:out = "" . l:file.name . ":"
    let l:done = []
    let l:srcfound = 0

    for l:s in l:seen
      if l:s == l:file.name
        let l:srcfound = 1
        break
      endif
    endfor

    if l:srcfound == 1
      continue
    endif

    call add(l:seen, l:file.name)

    if len(l:file.dependencies) > 0
      for l:dep in l:file.dependencies
        let l:found = 0

        for l:d in l:done
          if l:d == l:dep.name
            let l:found = 1
            break
          endif
        endfor

        if l:found == 0
          let l:out = l:out . " " . l:dep.name
          call add(l:done, l:dep.name)
        endif
      endfor

      "call Output(l:file.name)
      "call Output(l:out)
      call add(l:lines, l:out)
    endif

  endfor

  if !isdirectory("obj")
    call mkdir("obj")
  endif

  call writefile(l:lines, "obj/dependencies.iffe", "b")

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeClean
"
" Recursively delete the "bin", "lib" and "obj" folders if any of them exist.
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeClean()

  if isdirectory("bin")
    call delete("bin", "rf")
  endif

  if isdirectory("lib")
    call delete("lib", "rf")
  endif

  if isdirectory("obj")
    call delete("obj", "rf")
  endif

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeBuild
"
" Iterate through all of the library projects and build them, then do the same
" for the executable projects. Finally store the updated dependencies from the
" source files into the database.
"
" ctx - The encapsulating system
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeBuild(ctx)

  for l:project in a:ctx.projects
    if l:project.executable == 0
      call ProjectBuild(l:project)
    endif
  endfor

  for l:project in a:ctx.projects
    if l:project.executable == 1
      call ProjectBuild(l:project)
    endif
  endfor

  call IffeStoreDependencies(a:ctx)

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeOptions
"
" Output a number of post build options and map them to buffer specific key
" presses.
"
" ctx - The encapsulating system
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeOptions(ctx)

  call Output("-----------------")
  call Output("Press 'r' to rebuild")
  call Output("Press 'c' to clean")
  call Output("Press 'q' to exit")
  nnoremap <buffer> q :q!<CR>
  nnoremap <buffer> r :call IffeMain()<CR>
  nnoremap <buffer> c :call IffeClean()<CR>

endfunction

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" IffeMain
"
" Clear the buffer (in case it is a subsequent run), create the encapsulating
" structure and start the main processes.
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
function IffeMain()

  execute("normal! ggdG")

  let l:iffe = IffeCreate()
  call IffeBuild(l:iffe)
  call IffeOptions(l:iffe)

endfunction

call IffeMain()
```

Edit: Also uploaded to GitHub: https://github.com/osen/iffe.vim
I am probably going to keep working on it because it is really handy for platforms that CMake doesn't really deal well with such as Megadrive / GBA SDK, Emscripten, Android NDK compilers.


----------



## Mjölnir (May 30, 2020)

Dr_Phoenix said:


> Hi people!
> Please, post here useful scripts which can help to do some useful or difficult operation on FreeBSD OS.


Found a script  on one of my old laptops to attach/insert a geom(4) I/O scheduler - RTFM gsched(8).

An I/O scheduler is at least useful on a UFS (or alike) system; I don't know and didn't try with ZFS.  Other use cases might be a DB on a dedicated geom(4) device.
The I/O scheduler can significantly increase throughput and interactivity with concurrent tasks, as described by the authors of gsched(8).
I can could verify that - the system runs much "smoother" when running background tasks with heavy disk I/O.  The script served me well for years.
The script might violate some guidelines for rc scripting that I was not aware of.
Very Likely it has bugs, since I was the only user.
Drop me a note and I'll fix that.
If a few others could prove it's safe, it could go to /usr/share/examples/etc/rc.d or even in the base.
Suggested directories:{/usr/local}/etc/rc.d/geom_sched, {/usr/local}/libexec/fs_summarize.awk
or the respective directories in /usr/share/examples
and rc.geom_sched.conf is for insertion in rc.conf{.local}
The other script fs_summarize.awk is useful to determine the parameters for newfs(8) or just if you want some info about a FS or directory.
Just in case this is needed: the standard FreeBSD BSD license applies to the scripts, the snippet rc_geom_sched.conf obviously does not need any license.


----------



## kpedersen (Jun 2, 2020)

*Moving UNIX domain sockets*
Not really a script as such but more an example that UNIX domain sockets can be moved (not copied). This is really handy for allowing X11 access into a Jail.


```
UNIQUE=$$
Xephyr :$UNIQUE &

# Wait until the socket exists

mv /tmp/.X11-unix/X$UNIQUE /jails/myjail/tmp/.X11-unix/X0
jexec myjail xterm -display :0
```

*Finding absolute path of script or program*
Also, a handy way to get the absolute path to your script (or more usefully, the prefix) without faffing with procfs and all that other stuff. This is useful because sometimes relative paths are not supported or not desired.


```
PREFIX="$(cd "$(dirname "$(which "$0")")" && cd .. && pwd)"

# which "$0" ensures that a path is returned if the program was run from $PATH
# dirname ensures that the directory containing the program (i.e bin) is returned
# cd, cd .., pwd ensures that an absolute path is given by going into the directory and using pwd.
```

It seems a bit "dirty" but I also use this (via popen) in C++ and perl. It is the only guaranteed way that I have found over the years. And I have tried quite a few!


----------



## Dmitry E. Gouriev (Jul 15, 2020)

Hi all!
There is A simple useful script for simple intrusion detection (FreeBSD + ipfw) in the *Firewalls* forum and also a discussion on similar tools in subsequent thread.


----------



## olli@ (Jul 15, 2020)

kpedersen said:


> Not really a script as such but more an example that UNIX domain sockets can be moved (not copied). This is really handy for allowing X11 access into a Jail.
> 
> 
> ```
> ...


Does that also work if /tmp and /jails are on different file systems? Because in that case a you’re technically copying, not moving.


> Also, a handy way to get the absolute path to your script (or more usefully, the prefix) without faffing with procfs and all that other stuff. This is useful because sometimes relative paths are not supported or not desired.
> 
> 
> ```
> ...


The realpath(3) function (and the corresponding realpath(1) command) is very useful in this context. It converts relative paths to absolute paths _and_ resolves symbolic links. In shell scripts I'm using the following to find out the script’s directory:

```
SCRIPTDIR=$(realpath "${0%/*}")
```
So, to get the prefix, that would be rather simple:

```
PREFIX=$(realpath "${0%/*}/..")
```
Sometimes I resort to writing a script in zsh, because FreeBSD's sh is missing quite a few features (it’s not a POSIX-compatible shell). In that case, the prefix can be found without calling any external programs, so this is most efficient:

```
PREFIX=${0:A:h:h}
```
Explanation: Basically, the “`:A`” modifier is equivalent to realpath(3), and the “`:h`” modifier is equivalent to dirname(3).

By the way, in Python you would do this:

```
from sys import argv
from os.path import realpath, dirname

prefix = dirname(dirname(realpath(argv[0])))
```
Other languages like Perl or Ruby also have bindings to the standard library functions realpath(3) and dirname(3), so it basically works the same there, too (modulo different syntax, of course). C and C++ can use those functions directly anyway, of course – the former is in `<stdlib.h>` and the latter is in `<libgen.h>`. Both are POSIX / SUS standards.


----------



## kpedersen (Jul 15, 2020)

olli@ said:


> Does that also work if /tmp and /jails are on different file systems? Because in that case a you’re technically copying, not moving.


Unfortunately no, I don't think that is possible. Perhaps with something like nullfs? You can trick it into opening the socket on the other FS?

Perhaps it is time for Zirias's project to come in handy? : https://forums.freebsd.org/threads/new-tool-remusock-remote-unix-socket-access.76026/




olli@ said:


> The realpath(3) function (and the corresponding realpath(1) command) is very useful in this context. It converts relative paths to absolute paths _and_ resolves symbolic links.



From what I could see, this doesn't work for things in PATH? I.e *realpath ls* returns /home/kpedersen/ls


----------



## olli@ (Jul 15, 2020)

kpedersen said:


> From what I could see, this doesn't work for things in PATH? I.e *realpath ls* returns /home/kpedersen/ls


Yes, it _does_ work for things in PATH. When you call a shell script via PATH, $0 always includes the directory in which it was found.


----------



## kpedersen (Jul 15, 2020)

olli@ said:


> $0 always includes the directory in which it was found.



Oh, I thought $0 would be just the program name if called from PATH. That is why I include *which "$0"* in my slightly monstrous alternative.


----------



## olli@ (Jul 15, 2020)

By the way, some generic advice for writing shell scripts, for those wo are not already experts …  

Try to write shell scripts using /bin/sh only. This will make the scripts most portable and doesn't require people to install a specific shell if you share them with others. Note that /bin/sh scripts will usually work without change with POSIX-compatible shells, too (zsh, ksh, bash). If you absolutely have to use POSIX features that are not supported by FreeBSD's /bin/sh, I suggest using ksh because it most closely resembles the POSIX standard, and also works with bash and zsh. Avoid using bashisms or zshisms that don't work anywhere else.

Begin your script with `set -Cefu`.

`-C` (“noclobber”) prevents the script from overwriting files with `>` accidentally. If you need to overwrite a file on purpose _and_ you're absolutely sure that it’s the correct thing to do, you can use `>|` instead to override the -C option, or enclose the respective code between `set +C` and `set -C`, or simply `rm -f` the file beforehand.
`-e` (“errexit”) causes the script to terminate immediately if a command returns an error (i.e. a non-zero return code). See the sh(1) manual page for details. If you know that a command may return a non-zero exit code, but you want to continue anyway, append `|| true`, or (better) put it into an `if` clause and print a message to the user if appropriate.
`-f` (“noglob”) disables globbing, also known as pathname expansion or filename generation using wildcards like `*`. This is often a cause of subtle bugs and malfunctions, so it’s best to disable it altogether. To create a list of files, it’s better to use things like `ls | grep ...` or find(1) which is much more powerful.
`-u` (“nounset”) causes the script to print an error message and exit immediately if you try to use a variable that has not been set before. `unset FOO; echo $FOO` will trigger this, for example. This is useful to quickly detect typos in variable names. If you need to expand a variable that might be unset (and you known what you’re doing), `${FOO-}` will prevent the error (if FOO is unset, it will expand to an empty string). Again, see the sh(1) manual page for details.
These options are very helpful to write scripts that are more robust and have a lower risk of malfunctions.

The next line in most of my scripts is: `ME=${0##*/}`
That sets the variable ME to the basename of the script, so it can conveniently be used in error messages and similar, like in this little helper function:

```
Err ()
{
        echo "${ME}: $*" >&2
        exit 1
}
```
So you can write things like this:

```
test -f "$INFILE" || Err "File not found: $INFILE"
```

If in doubt, always write variable expansions in double quotes.
If a variable might begin with a dash, use `--` to prevent it from being confused with an option if appropriate, e.g.:
`ls -l -- "$MYDIR"`

By the way, do not use backticks (``foo``) for command substitution. Nesting them is difficult, they can be confused with single quote characters (`'foo'` looks very similar), and the quoting rules involving backticks are complicated. Better use the alternative `$(foo)` syntax. This can be nested arbitrarily deep without having to use heaps of backslashes, and the quoting rules are more intuitive.

If you need to debug a shell script, the -v and -x options are very useful: `sh -vx ./myscript`

`-v` causes the script code to be printed as it is read from the file during execution.
`-x` causes the resulting commands (after variable expansion etc.) to be printed right before they're executed. This is especially useful to see what your script is actually doing.

Happy hacking!


----------



## kpedersen (Jul 15, 2020)

olli@ said:


> `-u` (“nounset”) causes the script to print an error message and exit immediately if you try to use a variable that has



That is so very useful for constructs like:

rm -rf "${LOGDIR}/${DATE}"

Where you just happen to leave those variables unassigned in an incorrect code-path. XD


----------



## decuser (Jul 22, 2020)

*Sleep daemon for monitoring battery life and putting laptop to sleep when needed*

Here's a useful set of scripts for creating a daemon to monitor battery life and sleep the system when it's critically low that works without a desktop (it also works with TWM, but it's not required). The original discussion on this topic is here, the workhorse is the monitor, which is a modified version of the script DutchDaemon originally posted here. The script basically checks the battery level every 5 minutes and when it drops to 10%, it sets a 2 minute timer and checks again, if it's getting lower at that time, it sends an email to root warning of imminent shutdown and 2 minutes after that sleeps the system.

I use the daemon because I have not been using a DE lately and my laptop kept powering down when the battery got low. This keeps that from happening.

The zipfile - sleepd.zip contains these three files:

1. rc-sleepd - the rc script to control the daemon, gets installed in /etc/rc.d
2. sbin-sleepd - the script that does the actual monitoring, gets installed in /usr/sbin
3. install.sh - a simple install script to install the daemon and remind you how to enable the service

To install, just download the zipfile as a normal user with wheel privileges and:

`unzip sleepd.zip
cd sleepd
sudo sh ./install.sh`

and

`sudo sysrc -f /etc/rc.conf sleepd_enable="YES"
sudo service sleepd start`

20200722-1418 wds - updated the scripts to use /usr/local prefixes in line with hier()


----------



## kpedersen (Aug 15, 2020)

OpenSSH on Windows is kinda bearable compared to remote powershell. The biggest issue is no native tmux / screen support.
I was not happy with the existing practice of using a tabbed console or tmux on the local host and opening multiple ssh connections so I made my own tool.









						GitHub - osen/vimux: A tmux clone for Windows
					

A tmux clone for Windows. Contribute to osen/vimux development by creating an account on GitHub.




					github.com
				




Basically run *bin/vimux* and then you can use tmux-like shortcuts like *ctrl-c* to create new terminals within the same session.

(the underlying platform enabling this is vim and its virtual-pty support


----------



## olli@ (Aug 26, 2020)

In another thread I mentioned this shell function, and *mjollnir* asked me to put it here, so here it is.
It uses zsh syntax and is meant to be put in your ~/.zshrc, but I guess it could be adapted to bash without much effort.

Alternatively you can turn it into a standalone script: Remove the first line “`inplace ()`” and the outermost level of braces, and prepend the line “`#!/usr/bin/env zsh`”. Save the script with the name inplace in some bin directory (so it can be found via your `$PATH` setting), and make it executable: `chmod 755 inplace`. Make sure you have shells/zsh installed.

```
inplace ()
{
        #   Execute a command that reads from a file and writes to stdout,
        #   and move the output back to the input file.  The file name must
        #   be the last argument.  Timestamps (atime, mtime) and permissions
        #   are preserved.  A backup of the original file is retained with the
        #   extension ".BAK".  If an error occurs, the orignal file is not
        #   changed, and a temporary file is kept in the same directory
        #   (unless it is empty).

        emulate -L zsh
        local LASTARG="${@[-1]}"
        local BAKNAME="$LASTARG".BAK
        local TMPNAME="$LASTARG".inplace_tmp

        echo "Note: Keeping backup in $BAKNAME" >&2
        rm -f -- "$TMPNAME" \
        && "$@" > "$TMPNAME" \
        && touch -r "$LASTARG" -- "$TMPNAME" \
        && chmod 0$(stat -f"%OLp" -- "$LASTARG") "$TMPNAME" \
        && mv -f -- "$LASTARG" "$BAKNAME" \
        && mv -f -- "$TMPNAME" "$LASTARG" \
        || {
                if [[ ! -s "$TMPNAME" ]]; then
                        rm -f -- "$TMPNAME"
                fi
                return 1
        }
}
```
Usage example:
`inplace iconv -f ISO8859-16 -t UTF-8 somefile.txt`


----------



## Mjölnir (Aug 26, 2020)

-> shells/zsh-completions via bug report + patch?


----------



## olli@ (Aug 26, 2020)

mjollnir said:


> -> shells/zsh-completions via bug report + patch?


That function is not a zsh completion, it’s just a normal shell function.


----------



## ccammack (Sep 26, 2020)

Here's my current backup script in case it helps other new users with similar needs.

All of my data from multiple computers fits on a single hard drive, so I back it all up to a central FreeBSD server with a removable drive tray and store the drives offsite.

The morning protocol takes about 15 seconds; if the programmable LED is flashing green, I open the tray and swap the drive, then take it with me when I leave. At night I bring home an older backup drive and then repeat the swap procedure the next morning.

The script runs `zfs scrub` on insertion every Saturday, so all of the backup drives get scrubbed for errors once every few weeks as they rotate through.

I'm currently backing up a Windows desktop, an Ubuntu laptop, a FreeBSD server, and the backup server itself to the external drive.

The system detects drive insertion using this `devd` config:


```
# cat /usr/local/etc/devd/backup.conf
notify 100 {
    # insert backup drive
    match "system" "GEOM";
    match "subsystem" "DEV";
    match "type" "CREATE";
    match "cdev" "gpt/backup";
    action "su -l backup -c 'doas /usr/local/sbin/backup.sh --on-insert' &";
};

notify 100 {
    # eject backup drive
    match "system" "GEOM";
    match "subsystem" "DEV";
    match "type" "DESTROY";
    match "cdev" "gpt/backup";
    action "su -l backup -c 'doas /usr/local/sbin/backup.sh --on-eject' &";
};
```

The script runs using `doas` for a dedicated user with this config:


```
# cat /usr/local/etc/doas.conf
permit nopass backup as root cmd /usr/local/sbin/backup.sh
```

The backup script itself is attached below.


----------



## Rudy (Nov 2, 2020)

Here is a script to run in the terminal to give you some info on what your named server is doing.  


```
#!/usr/local/bin/perl
#
# Quick script to see that the DNS server is doing
# Fri Oct 30 16:34:29 PDT 2020, created, rudy
#
# requirements:
# pkg install p5-Term-ReadKey
# pkg install p5-Term-ANCIScreen
# ----------------------------------------------------------------------

use Term::ReadKey;
use Socket;
use POSIX qw(ceil floor);
use Term::ANSIScreen qw/:color :cursor :screen :keyboard :constants/;
use strict;

our (%h, %r, %lh, %lr);   # hits, requests, and last for those two
our (%dns, %stats);       # DNS cache, and RDNC output
our ($width, $height);   # terminal size
our $hostname = `hostname`;
chomp($hostname);

# set 'network' to your DNS server's ip block
# example, your DNS server is 10.8.2.3 or 10.8.2.4 then use
our $network = '10.8.1.0/28';  # DNS server Range (used in TCPDUMP)
our $port = 53;                   # not sure this will ever change
our $countPerCycle = 1000;        # count flag for TCPDUMP

# ----------------------------------------------------------------------

print "Welcome, starting TCPdump to gather snapshot of current DNS requests.\nStandby ......\n\n";
while (1) {
    &tcpdump;
    my ($lastwidth, $lastheight) = ($width, $height);
    ($width, $height) = GetTerminalSize ();
    print cls() if ($height != $lastheight || $width != $lastwidth);  #wipe screen on resize
    locate 1, 1;  # move cursor to top left
    &getStats;
    &header;
    &top10;
    &footer;
}

sub tcpdump {
    %lr = %r;
    %lh = %h;
    open TCPDUMP, "tcpdump -n -c $countPerCycle dst port $port and dst net $network 2> /dev/null |" or die "No tcpdump\n";
    while (<TCPDUMP>) {
        # 13:14:18.664904 IP 52.119.118.12.42467 > 208.69.40.3.53: 26522+ A? l3.dca0.com. (29)
        # this could probably use refinements... version 0.1
        my @a = split(' ');
        my $ip = $a[2];
        $ip =~ s/(\.\d+)$//; #remote port;
        $h{$ip}++; # easy to spoof...
        if (/Flags/) {
            $r{'Flags'}++;
        } elsif ($a[6] eq '[1au]') {
            $r{"$a[7] $a[8]"}++;
        } else {
            $r{"$a[6] $a[7]"}++;
        }
    }
    close TCPDUMP;
}


sub top10 {
    # started out as top10, but let's just max out to match terminal size.
    my $top =  floor($height/2) - 3;

    # print top IPs doing requests
    print colored ['black on white'], sprintf("%5s      %17s %45s\n","Hits", "IP","Hostname");
    my $count = 0;
    foreach my $ip (sort {$h{$b} - $lh{$b} <=> $h{$a} - $lh{$a} }  keys %h) {
        if ($top > $count++) {
            print " "x$width . "\r";  # clear line
            print colored ['bold white'], sprintf("%5i ",$h{$ip}),
                  colored ['bold green'], sprintf("+%-4i",$h{$ip} - $lh{$ip}),
                  colored ['red'], sprintf("%17s",$ip),
                  colored ['yellow'], sprintf(" %45s",&hostname($ip)),
                  "\n";
        } elsif ($count > 1000) {
            delete($h{$ip});
        }
    }

    # Print out the 'most popular' lookups
    $count = 0;
    my $half = floor($width/2);
    my $halfminus1 = $half-1;
    print colored ['bold black on white'], sprintf("%-${halfminus1}s\n", "Total Hits      Request");
    foreach my $req (sort {$r{$b} <=> $r{$a}} keys %r) {
        if ($top > $count++) {
            print " "x$width . "\r";
            print colored ['bold white'], sprintf("%5i ",$r{$req}),
                  colored ['bold green'], sprintf("+%-4i",$r{$req} - $lr{$req});
            #$req =~ s/(.{$half}).*/$1/,
            print colored ['bold blue'], $req, "\n";
        } elsif ($count > 1000) {
            delete($r{$req});
        }
    }
    return if ($width < 70);
    $count = 0;

    # Print out the 'most popular' lookups for this last data cycle
    print up($top+1), right($half);
    print colored ['bold black on white'], sprintf("%-${half}s\n", "New Hits      Request");
    foreach my $req (sort {$r{$b} - $lr{$b} <=> $r{$a}- $lr{$a} } keys %r) {
        if ($top > $count++) {
            print right($half),
                  colored ['bold green'], sprintf("+%-4i",$r{$req} - $lr{$req});
            my $max_string_size = $half-5;
            $req =~ s/(.{$max_string_size}).*/$1/,
            print colored ['bold blue'], $req, "\n";
        }
    }
    %lr = {};
}

sub hostname {
    my $ip = shift;
    $dns{$ip} ||= gethostbyaddr(inet_aton($ip), AF_INET) || 'No.rDNS';
    return $dns{$ip};
}

sub getStats {
    # get clients from 'rndc' ouput and use 'ps' to get CPU usuage of bind
    open RNDC, "rndc status |" or return undef;
    local $/ = undef;
    $_ = <RNDC>;
    close RNDC;
    $stats{cpu} = `ps axo %cpu,comm | grep named`;
    $stats{cpu} =~ s/ named.*/%/s;
    /version: BIND (\S+)/s || return undef;
    $stats{version} = $1;
    if (m,(recursive clients: \d+/\d+/\d+),s) {
        $stats{clients} = $1;
    }
}

sub header {
    # stuffed this in a subroutine so you can change it to what you want!
    my $now_string = localtime;
    print colored ['black on yellow'], sprintf("%-${width}s","$hostname    $now_string");
}

sub footer {
    print " "x$width . "\r";  # clear line
    my $size = $width - length("CPU: $stats{cpu}, BIND $stats{version}") - 1;
    my $now_string = localtime;
    print colored ['black on yellow'], sprintf("CPU: $stats{cpu}, BIND $stats{version} %${size}s\n",$stats{clients});
}
```


----------



## kpedersen (Dec 10, 2020)

This tmux config (.tmux.conf) will ensure that the status bar is only visible if you have more than one window.


```
set-option -g status off

set-hook -g session-window-changed \
  'if-shell \
    "test $(tmux list-windows | wc -l) -eq 1" \
    "set-option status off" "set-option status on"'
```


----------



## olli@ (Mar 24, 2021)

I recently wrote a little Python script to display various CPU graphs (frequency, temperature, load) in a window on my X11 desktop.
It might be useful for others, too, so I put it on this web page. There are also *screen shots*.
The script may also serve as an example how to write simple X11 applications in Python. It also demonstrates how to retrieve and handle sysctl values in Python on FreeBSD.
Please read the instructions on the web page carefully. In particular, you have to install a few dependencies (Python3 for the script, Pillow for the image handling, Tkinter for the X11 widgets).


----------



## Vull (May 21, 2021)

This may seem trivial, but it took longer to figure out than anticipated, so, why not share it?


```
#!/bin/sh
# keycodes - this checks out on FreeBSD 13.0, Debian 10.9, Ubuntu 20.04, LM 20.1
# 2021-05-17 m 099/jch

# Notes: dd returns "" for both null and lf (ctrl-@ and ctrl-J). This script
# returns "nl" (newline) for both. Ctrl-@ represents byte code 0 (ascii "nul").
# Ctrl-J nicknames: linefeed (lf) = newline (nl) = dec 10 = octal 012 = hex 0a.
# TERM values tested: xterm, xterm-256color, linux
# Emulations tested: Konsole, "xterm", MATE-terminal, FreeBSD &GNU virtual terms

#--- what syntax style does this shell implementation use?
if [ "$(echo '\40')" = " " ]; then shsyntax=older
elif [ $'\177' = $'\x7f' ]; then shsyntax=newer
else shsyntax=unfamiliar
fi
#--- initialize variables
case "$shsyntax" in
  ("older") nul='\000'; lf='\012'; del='\177'
    ;;
  ("newer") nul=$'\000'; lf=$'\012'; del=$'\177'
    ;;
  (*)
    echo; echo "Unfamiliar /bin/sh syntax. Bailing out, sorry."; echo
    exit 1
    ;;
esac
#--- let's get it started
cat << EOF
Press ENTER to exit, or any other key to see key codes and sequences.
(Some keys may be intercepted by the OS, terminal, or terminal emulation.)
EOF
notraw=$(stty -g)
stty raw
stty -echo
saveifs=$IFS
IFS=
loop=1
while [ "$loop" ]; do 
  key=$(dd bs=1 count=1 2>/dev/null) # bytes out on std oput, std err=info+error
  if [ "$key" = "" ]; then key=$lf; fi
  #--- check for control characters and whitespace
  if [ "$(echo "$key" | tr -d [:cntrl:])" = "" ]||[ "$key" = " " ]; then
    #--- look up human readable ascii nicknames for control chars and spacebar
    asc=$(echo -n "$key" | od -a | awk 'BEGIN{FS=" "}{print $2}')
  else #--- not a control char or " "
    asc=$key #--- this key char should be displayable as is
  fi
  echo -n $asc" " #--- display the character or it's nickname
  if [ "$asc" = "cr" ]; then loop= ; fi
done
IFS=$saveifs
stty "$notraw"
stty echo
echo #--- start new line on terminal
exit 0
```


----------



## Vull (May 22, 2021)

Same as in previous post, but improved to handle utf-8 multibyte characters. Also followed some of olli@'s advice from post #333. The bits about sh syntax are just there to make it work properly on GNU implementations of the "sh" shell, which are not as well caught up to the more recent posix standards. This might also allow it to work on older FreeBSD sh versions.

```
#!/bin/sh
# keycodes - this is working on FreeBSD 13.0, Debian 10.9, Ubuntu 20.04, LM 20.1
# 2021-05-17 m 099/jch

# Notes: dd returns "" for both null and lf (ctrl-@ and ctrl-J). This script
# returns "nl" (newline) for both. Ctrl-@ represents byte code 0 (ascii "nul").
# Ctrl-J nicknames: linefeed (lf) = newline (nl) = dec 10 = octal 012 = hex 0a.
# TERM values tested: xterm, xterm-256color, linux
# Emulations tested: Konsole, "xterm", MATE-terminal, FreeBSD &GNU virtual terms

set -efu # errexit, noglob, nounset
myname=${0##*/}
shsyntax=
lf=
notraw=
saveifs=
loop=
byt=
hex=
utf8ch=
ucount=
uexpect=
asc=

#--- what syntax style does this shell implementation use?
if [ "$(echo '\40')" = " " ]; then shsyntax=older
elif [ $'\177' = $'\x7f' ]; then shsyntax=newer
else shsyntax=unfamiliar
fi
#--- initialize variables
case "$shsyntax" in
  ("older") lf='\012'
    ;;
  ("newer") lf=$'\012'
    ;;
  (*)
    echo; echo "Unfamiliar /bin/sh syntax. Bailing out, sorry."; echo
    exit 1
    ;;
esac
#--- let's get it started
cat << EOF
$myname - Press ENTER to exit, or any other key to see key codes and sequences.
(Some keys may be intercepted by the OS, terminal, or terminal emulation.)
EOF
notraw=$(stty -g)
stty raw
stty -echo
saveifs=$IFS
IFS=
ucount=0
loop=1
while [ "$loop" ]; do
  byt=$(dd bs=1 count=1 2>/dev/null)
  #--- dd sends bytes out on std oput, std err gets informational oput + errors
  if [ "$byt" ]; then
    hex=$(echo $byt | od -t x1 | awk 'BEGIN{FS=" "}{print $2}') #--- hex
  fi
  if [ "$byt" ]&&[ "$hex" \> "7f" ]; then
    #--- utf8 multibyte sequence handler
    ucount=$(($ucount+1))
    case $ucount in
      (1)
        utf8ch=$byt
        if [ "$hex" \> "bf" ]&&[ "$hex" \< "e0" ]; then #--- c0..df leadin
          uexpect=2
        elif [ "$hex" \> "df" ]&&[ "$hex" \< "f0" ]; then #--- e0..ef leadin
          uexpect=3
        elif [ "$hex" \> "ef" ]&&[ "$hex" \< "f8" ]; then #--- f0..f7 leadin
          uexpect=4
        else
          echo -n $myname': Invalid utf8 leadin byte="x'$hex'" '
          ucount=0
        fi
        ;;
      (*)
        if [ "$hex" \> "7f" ]&&[ "$hex" \< "c0" ]; then #--- 80..bf contin byte
          utf8ch=$utf8ch$byt
          if [ $ucount -eq $uexpect ]; then
            echo -n $utf8ch" " #--- display the multi-byte utf8 character
            ucount=0 #--- reset counter for next multi-byte utf8 sequence
          fi
        else
          echo -n $myname': Invalid utf8 continuation byte="x'$hex'" '
          ucount=0
        fi
        ;;
    esac
  else
    #--- ascii or utf8 single-byte handler for bytes in hex [00..7f] range
    if [ "$byt" = "" ]; then byt=$lf; fi #--- either nul or lf -> lf
    if [ $ucount -gt 0 ]; then
      echo -n $myname': Invalid utf8 character sequence '
      ucount=0
    #--- check for control characters and whitespace
    elif [ "$(echo "$byt" | tr -d [:cntrl:])" = "" ]||[ "$byt" = " " ]; then
      #--- look up human readable ascii nicknames for control chars and spacebar
      asc=$(echo -n "$byt" | od -a | awk 'BEGIN{FS=" "}{print $2}')
    else #--- not a control char or " "
      asc=$byt #--- this key char should be displayable as is
    fi
    echo -n $asc" " #--- display the character or it's nickname
    if [ "$asc" = "cr" ]; then loop= ; fi
  fi
done
IFS=$saveifs
stty "$notraw"
stty echo
echo #--- start new line on terminal
exit 0
```


----------



## zirias@ (Nov 1, 2021)

Just a tiny script to check your /etc/rc.conf for consistency with `ifconfig_*` variables when you have _lots_ of interfaces:

```
#!/bin/sh

if=${1:-lo0}

. /etc/rc.subr
. /etc/network.subr

load_rc_config netif
echo -n "${if}     : "
ifconfig_getargs ${if}

if ipv6if ${if}; then
    echo -n "${if} (v6): "
    ifconfig_getargs ${if} ipv6
else
    echo no IPv6
fi
```
Example usage:

```
# ./rc_ifconfig.sh bridge1
bridge1     : inet 192.168.99.1 netmask 255.255.255.0 addm vtnet3 addm lagg0v100
bridge1 (v6): inet6 2001:<redacted>:99::1 prefixlen 80 auto_linklocal
```

You can check everything you configured manually for an interface is actually there. Duplicate variables aren't that easy to spot in large configs, I actually found one using that script (and the problem just didn't manifest because other custom scripts happened to correct the interface's config later)


----------



## kpedersen (Dec 22, 2021)

I needed to grab the entire Debian i386 & amd64 repo and yet I didn't really feel like logging into a Linux system to do so. Instead I wrote this (fairly substantial) Awk script 


```
#!/usr/bin/awk -f

# Example sources.list
# deb file:///repodir/bullseye-security/non-free/amd64 ./

############################################################################
# main
############################################################################
function main()
{
  add_source("http://deb.debian.org/debian",
    "bullseye", "main contrib non-free", "i386 amd64")

  add_source("http://deb.debian.org/debian",
    "bullseye-updates", "main contrib non-free", "i386 amd64")

  add_source("http://deb.debian.org/debian-security",
    "bullseye-security", "main contrib non-free", "i386 amd64")

  fetch()
  verify()
}

############################################################################
# add_source
############################################################################
function add_source(url, dist, components, archs,    curr, sc, sa, c, a)
{
  split_whitespace(components, sc)
  split_whitespace(archs, sa)

  for(c in sc)
  {
    for(a in sa)
    {
      curr = ++ALLOC
      SOURCES[curr] = curr
      SourceUrl[curr] = url
      SourceDist[curr] = dist
      SourceComp[curr] = sc[c]
      SourceArch[curr] = sa[a]
      SourcePackageDir[curr] = dist "/" SourceComp[curr] "/" SourceArch[curr]
    }
  }
}

############################################################################
# verify
############################################################################
function verify(    source)
{
  for(source in SOURCES)
  {
    verify_packages(source)
  }
}

############################################################################
# fetch
############################################################################
function fetch(    source)
{
  for(source in SOURCES)
  {
    fetch_metadata(source)
  }

  for(source in SOURCES)
  {
    fetch_packages(source)
  }
}

############################################################################
# verify_packages
############################################################################
function verify_packages(source,    input, line, tokens, tc, filename, checksum)
{
  input = SourcePackageDir[source] "/Packages"
  filename = ""
  checksum = ""

  if(!exists(input))
  {
    return
  }

  while(getline line < input == 1)
  {
    tc = split_whitespace(line, tokens)

    if(tc >= 2)
    {
      if(tokens[0] == "Filename:")
      {
        filename = tokens[1]
      }
      else if(tokens[0] == "SHA256:")
      {
        checksum = tokens[1]
      }
    }

    if(filename != "" && checksum != "")
    {
      print("Verifying: " filename)

      if(!exists(SourcePackageDir[source] "/" filename))
      {
        error("Package does not exist")
      }

      if(sha256(SourcePackageDir[source] "/" filename) != checksum)
      {
        error("Package checksum did not match")
      }

      filename = ""
      checksum = ""
    }
  }

  close(input)
}

############################################################################
# fetch_packages
############################################################################
function fetch_packages(source,    input, line, output, tokens, tc, skip, filename, checksum, url)
{
  input = SourcePackageDir[source] "/Packages.orig"
  output = "Packages.part"
  filename = ""
  checksum = ""

  if(exists(SourcePackageDir[source] "/Packages"))
  {
    return
  }

  touch(output)

  while(getline line < input == 1)
  {
    skip = 0
    tc = split_whitespace(line, tokens)

    if(tc >= 2)
    {
      if(tokens[0] == "Filename:")
      {
        filename = tokens[1]
        skip = 1
        print("Filename: " basename(filename)) > output
      }
      else if(tokens[0] == "SHA256:")
      {
        checksum = tokens[1]
      }
    }

    if(!skip)
    {
      print(line) > output
    }

    if(filename != "" && checksum != "")
    {
      url = SourceUrl[source] "/" filename
      filename = basename(filename)

      if(!exists(SourcePackageDir[source] "/" filename))
      {
        download(url, SourcePackageDir[source] "/" filename, checksum)
      }
      else
      {
        print("Package exists [" filename "]")
      }

      filename = ""
      checksum = ""
    }
  }

  close(output)
  close(input)

  mv("Packages.part", SourcePackageDir[source] "/Packages")
  rm(SourcePackageDir[source] "/Packages.orig")
}

############################################################################
# fetch_metadata
############################################################################
function fetch_metadata(source,    dir)
{
  dir = SourcePackageDir[source]

  if(exists(dir "/Packages"))
  {
    return
  }

  if(exists(dir "/Packages.orig"))
  {
    return
  }

  download(SourceUrl[source] "/dists/" SourceDist[source] "/" SourceComp[source] "/binary-" SourceArch[source] "/Packages.xz", "Packages.xz")

  if(system("xz -d 'Packages.xz'") != 0)
  {
    error("Failed to decompress meta-data")
  }

  mkdir_p(dir)
  mv("Packages", dir "/Packages.orig")
}

############################################################################
# rm
############################################################################
function rm(path)
{
  if(system("rm '" path "'") != 0)
  {
    error("Failed to remove file")
  }
}

############################################################################
# mv
############################################################################
function mv(source, dest)
{
  if(system("mv '" source "' '" dest "'") != 0)
  {
    error("Failed to move file")
  }
}

############################################################################
# mkdir_p
############################################################################
function mkdir_p(path)
{
  if(system("mkdir -p '" path "'") != 0)
  {
    error("Failed to create diectory")
  }
}

############################################################################
# error
############################################################################
function error(message)
{
  print("Error: " message)
  exit(1)
}

############################################################################
# sha256
############################################################################
function sha256(path,    cmd, line)
{
  cmd = "sha256 -q '" path "'"
  #cmd = "sha256sum '" path "' | awk '{ print $1 }'"

  if(cmd | getline line != 1)
  {
    error("Failed to generate checksum")
  }

  close(cmd)

  return line
}

############################################################################
# download
############################################################################
function download(source, dest, checksum,    fetch_cmd)
{
  #fetch_cmd = "ftp -o"
  #fetch_cmd = "wget -O"
  fetch_cmd = "fetch -qo"

  print("Fetching: " basename(source))

  if(system(fetch_cmd " 'download.a' '" source "'") != 0)
  {
    error("Failed to download")
  }

  if(!checksum)
  {
    if(system(fetch_cmd " 'download.b' '" source "'") != 0)
    {
      rm("download.a")
      error("Failed to download")
    }

    if(sha256("download.a") != sha256("download.b"))
    {
      rm("download.a")
      rm("download.b")
      error("Checksums do not match")
    }

    rm("download.b")
  }
  else
  {
    if(sha256("download.a") != checksum)
    {
      rm("download.a")
      error("Checksums do not match")
    }
  }

  mv("download.a", dest)
}

############################################################################
# exists
############################################################################
function exists(path)
{
  if(system("test -e '" path "'") == 0)
  {
    return 1
  }

  return 0
}

############################################################################
# touch
############################################################################
function touch(path)
{
  if(system("touch '" path "'") != 0)
  {
    error("Failed to touch file")
  }
}

############################################################################
# basename
############################################################################
function basename(path,    ci, ls)
{
  ls = -1

  for(ci = 1; ci <= length(path); ci++)
  {
    if(substr(path, ci, 1) == "/")
    {
      ls = ci
    }
  }

  if(ls == -1) return path

  return substr(path, ls + 1)
}

############################################################################
# split_whitespace
#
# Split the string by any whitespace (space, tab, new line, carriage return)
# and populate the specified array with the individual sections.
############################################################################
function split_whitespace(line, tokens,    curr, c, i, rtn)
{
  rtn = 0
  curr = ""
  delete tokens

  for(i = 0; i < length(line); i++)
  {
    c = substr(line, i + 1, 1)

    if(c == "\r" || c == "\n" || c == "\t" || c == " ")
    {
      if(length(curr) > 0)
      {
        tokens[rtn] = curr
        rtn++
        curr = ""
      }
    }
    else
    {
      curr = curr c
    }
  }

  if(length(curr) > 0)
  {
    tokens[rtn] = curr
    rtn++
  }

  return rtn
}

BEGIN { main() }
```


----------



## grahamperrin@ (Dec 22, 2021)

Sleep (suspend)



decuser said:


> *Sleep daemon for monitoring battery life and putting laptop to sleep when needed*



ZFS

Can a _generic_ script take cache vdevs (physical devices) offline?

<https://openzfs.github.io/openzfs-docs/man/8/zpool-offline.8.html>

Audio, ZFS and sleep

For now, part of the sleep-related script at <https://forums.freebsd.org/posts/531858> uses non-generic labels to identify the devices to be off-lined:


```
# Prepare to disconnect USB flash drives that are used for L2ARC
#
# zpool offline copperbowl gpt/cache-copperbowl
zpool offline august gpt/cache-august
zpool offline august gpt/duracell
sync
```


----------



## Eric A. Borisch (Jun 10, 2022)

I finally got around to posting up my python-based shell-column-colorizer. A picture is really best here:






Be one of the first to try it out. No installer as it's just a stand-alone (py3) script. If there's interest a very trivial port could be put together.

Happy to take pull requests!


----------



## _al (Jun 10, 2022)

When 'gcc  -M'  dependency generation (between the object files and the C header files) does not quite fit, I use my own script  which does not count the standard C headers (I'm not going to edit them).
Actually, I have two similar scripts - one for UNIXes and one for Windows.

for UNIX:

```
use Cwd;
use Cwd 'abs_path';
use File::Basename;

my @includes=();
while(@ARGV and $ARGV[0] =~ /^-/){
    $_=shift;
    if (/^-(iquote|I)(.+)/){my @dirs=split(/:/,$2); push @includes, @dirs}
}

my $obj_file='';
my $dep_file='';

if(@ARGV){$obj_file= shift @ARGV}
if(@ARGV){$dep_file= shift @ARGV}
if(!$obj_file || !$dep_file){die "Not enough arguments"}
if(@ARGV){die "Too many arguments"}

my $source_file = fileparse($obj_file,qr/\.o/);
my $dir = dirname($obj_file);
my $cpp=$dir.'/'.$source_file.'.cpp';
my $c=$dir.'/'.$source_file.'.c';
my $scr=$dir.'/'.$source_file.'.scr'; # C++

if ( -e $cpp) {$source_file=$cpp} elsif ( -e $c) {$source_file=$c} elsif ( -e $scr) {$source_file=$scr} else {die "Source file not found"}

my @lines;
if(open(F_INP, $source_file)){
    @lines=<F_INP>;
    close(F_INP);
}

unless(open(F_OUT,'>>',$dep_file)){die "Could not open output file"}

sub find_first_dir_with_include_file {
    my $full_name='';
    for my $i (@includes){
        $full_name=abs_path($i.'/'.$_[0]);
        if( -e $full_name){last} else {$full_name='';}
    }
    return $full_name;
}

my $flag=0;
while(@lines){
    $line= shift @lines;
    if($line =~ /^s*#\s*include\s+"(.+)"/){
        if(!$flag){
            print F_OUT '$(_TMP_DIR)/'.$obj_file.': '.$source_file;
            $flag=1
        }
        my $name=$1;
        unless($name=~/\//){
            $name = dirname($source_file).'/'.$name;
        }
        print F_OUT ' '.&find_first_dir_with_include_file($name);
    }
}
print F_OUT "\n";
close(F_OUT);
```

for Windows:

```
use Win32;
use File::Basename;

my @includes=();
my $pch_file='';
while(@ARGV and $ARGV[0] =~ /^-/){
    $_=shift;
    if         (/^-p(.+)/){$pch_file=$1}
    elsif    (/^-(iquote|I)(.+)/){my @dirs=split(/;/,$2); push @includes, @dirs}
}

my $obj_file='';
my $dep_file='';

if(@ARGV){$obj_file= shift @ARGV}
if(@ARGV){$dep_file= shift @ARGV}
if(!$obj_file || !$dep_file){die "Not enough arguments"}
if(@ARGV){die "Too many arguments"}

fileparse_set_fstype( "MSDOS" );
my $source_file = fileparse($obj_file,qr/\.obj/);
my $dir= dirname($obj_file);
my $cpp=$dir.'/'.$source_file.'.cpp';
my $c=$dir.'/'.$source_file.'.c';
my $scr=$dir.'/'.$source_file.'.scr'; # C++

if ( -e $cpp) {$source_file=$cpp} elsif ( -e $c) {$source_file=$c} elsif ( -e $scr) {$source_file=$scr} else {die "Source file not found"}

my @lines;
if(open(F_INP, $source_file)){
    @lines=<F_INP>;
    close(F_INP);
}

unless(open(F_OUT,'>>',$dep_file)){die "Could not open output file"}

sub find_first_dir_with_include_file {
    my $full_name='';
    for my $i (@includes){
        $full_name=Win32::GetFullPathName($i.'/'.$_[0]);
        if( -e $full_name){last} else {$full_name='';}
    }
    return $full_name;
}

my $flag=0;
while(@lines){
    $line= shift @lines;
    if($line =~ /^s*#\s*include\s+"(.+)"/){
        if(!$flag){
            if($pch_file){
                print F_OUT $pch_file.': '.$source_file;
            } else {
                print F_OUT '$(_TMP_DIR)/'.$obj_file.': '.$source_file;
            }
            $flag=1
        }
        my $name=$1;
        if($name!~/\// && $name!~/\\/) {
            $name = dirname($source_file).'/'.$name;
        }
        print F_OUT ' '.&find_first_dir_with_include_file($name);
    }
}
print F_OUT "\n";
close(F_OUT);
```

I use them in makefiles as follows:

```
ifeq ($(PLATFORM),WINDOWS)
 _MAKEDEP_UTIL:=perl.exe $(UTIL_DIR)/makedep_win.pl
else
 _MAKEDEP_UTIL:=$(UTIL_DIR)/makedep_lin.pl
endif
```

and then:

```
ifeq ($(PLATFORM),WINDOWS) # [*]
define _CallMakeDepPCH
@$(_MAKEDEP_UTIL)  -p$(_PCH_NAME) $(_INCLUDES) $(USE_PCH) $(_PROJ_DEP)
endef
endif # [*]
define _CallMakeDep
@$(_MAKEDEP_UTIL)  $(_INCLUDES) $(1) $(_PROJ_DEP)
endef
```

and finally:

```
dep:
    $(foreach src,$(_OBJECTS),$(call _CallMakeDep, $(src)))
ifdef USE_PCH
    $(call _CallMakeDepPCH)
endif
```

Looks boring , but works


----------



## ziomario (Aug 30, 2022)

This is a very nice section of the FreeBSD forums. Very creative,very useful. I want to give "my" contribute. Today I've created the script below with the precious help of C. It should fix a bhyve behavior that someone could dislikes,I think. Infact sometimes between the processes you can see some bhyve ghosted vms that aren't working anymore and should be killed,but to do that manually is boring and it takes some time. Maybe if you use one or two virtual machines at the same time only you haven't the problem that I'm talking about,but usually I start a lot of vms and I have some troubles.


```
#!/bin/sh


setxkbmap it

#set -eux

vms="$(ps ax | awk '/bhyve: [vm]/{print substr($6,1)}')"

vncs="$(ps ax | awk '/vncviewer [0]/{print $6}')"

for vm in $vms; do

                session="${vm##vm}"

                echo "bhyve session = $vms"

                echo "vnc session = $vncs"

                echo "$session"

                if ! printf '%s\n' "${vncs}" | grep "${session}"; then

                                printf 'VNC session not found,destroying ghost vms\n'

                                bhyvectl --vm=$vms --force-reset

                                bhyvectl --vm=$vms --destroy

                sleep 5

                else

                                printf 'Found VNC session %s\n' "${session},no ghost vms found,not destroying them"

                fi

done
```


----------



## covacat (Sep 14, 2022)

last day of month
date -v -1d -j $(date -v +1m +%Y%m010000) +%d
or say you want to run a cron job in the last day of the month

```
#!/bin/sh
[ $(date -v +1d +%m) != $(date  +%m) ] || exit 0
# actual stuff here
```


----------

