Basic commands for custom scripts

Oracle

Regular Contributor
I'm trying to make some custom scripts and I have a few questions about basic operations that don't work as I expected.
(#!/bin/sh)
1) How can I check if a string a contains a substring b?
For example, a=abcde and b=abc.
The typical [[ $a == *"abc"* ]] doesn't work.
I've resorted to [ -z "${a##*$b*}" ], is that the only way?

2) How to convert a string from uppercase to lowercase or the opposite?
For example, a=ABCDE123. How to assign it to string b like "abcde123"?

3) Is there a command for case insensitive comparison of strings?
E.g. "ABC" to "abc".

4) Is there a way to get blkid to return device assignment (/dev/sda1, /dev/sda2, etc) based on exact match of partition label or UUID?

5) Can I log devices' mounting points?
E.g., device sda1 mounted to tmp/mnt/x
 

ColinTaylor

Part of the Furniture
1. Busybox's shell is not bash. Use what you're currently using. The alternatives would be more verbose and use external commands like grep or sed.

2. b=$(echo $a | tr A-Z a-z)

4.
Code:
# blkid | grep 'UUID="60D3-B8BD"' | cut -d: -f1
/dev/sda2

5. Log??? df, mount
 
Last edited:

joegreat

Very Senior Member
5. Log???
Some time ago I posted my script skeleton with the logging setup here - the purpose was a dynamic creation of swap file (to avoid writing on the same file all the time).
You can add some statements like the below ones for script debugging (un-comment the exec lines to active):
Bash:
# define and initiate the log-file
SCRLOG=/tmp/$(basename $0).log
touch $SCRLOG

# start script debugging (deatiled logging)
# exec 3>&1 4>&2 >$SCRLOG 2>&1

# ... all the script contecnt ...

# stop script debugging
# exec 1>&3 2>&4

exit $?
 

Oracle

Regular Contributor
Excellent help and very fast - thanks!
All the suggestions from ColinTaylor worked.
I made a little script to monitor what USB partition gets mounted, when and where.

As for the log, I sent the output to the logger and I can see it in the System Log page on the webUI of the router.
logger -t post-mount "Mounted $(mount | grep $1)"
Where is this log actually written? I hope it's not on the JFFS partition because it will wear it down.

Is it possible to parse and save the entire system log to a file on a USB? Apparently, there is some time between the moment the router boots up and USB partitions become available. I don't know how to handle that but I'd like to have the system history saved somewhere other than the JFFS.
 

ColinTaylor

Part of the Furniture
Where is this log actually written? I hope it's not on the JFFS partition because it will wear it down.
The syslog is located in /tmp with periodic copies made to /jffs. Wear is not an issue, this is a FAQ and has been discussed ad nauseam.

Is it possible to parse and save the entire system log to a file on a USB? Apparently, there is some time between the moment the router boots up and USB partitions become available. I don't know how to handle that but I'd like to have the system history saved somewhere other than the JFFS.
Yes, it's easily done. A cron job might be the simplest. way. There's also a user add-on script called Scribe which does the same thing and more besides. But unless you're willing to learn how it works (most users don't) it can cause more problems than it solves IMHO.
 

Martinski

Regular Contributor
3) Is there a command for case insensitive comparison of strings?
E.g. "ABC" to "abc".
The router's shell (IIRC, it's the Almquist shell, AKA Ash, ported into BusyBox) doesn't have a built-in basic method to do case-insensitive string comparisons (at least I haven't found one), so about a couple of years ago I ended up writing my own simple shell function that I can quickly call as needed in my own scripts:

Bash:
_strcmpCI_()
{
   if [ "$(echo "$1" | tr [A-Z] [a-z])" = "$(echo "$2" | tr [A-Z] [a-z])" ]
   then return 0 ; else return 1 ; fi
}
 

Oracle

Regular Contributor
Very good, thanks.
Now I'm left with 1 problem.
If I try to regularly parse the content of the system log (via cron) and append it to a file, I end up having the same messages repeated several times (of course).
So far, the only solution I see is to wipe out all the text from syslog.log after parsing, so the next iteration is only fresh content. Yet, I find it convenient to be able to see the log on the webUI for some time.
Btw, why is there a syslog.log-1?
 

Oracle

Regular Contributor
Very well. So if I could detect when syslog.log-1 has changed, I could parse it instead of syslog.log and keep continuous history.
 

ColinTaylor

Part of the Furniture
Very well. So if I could detect when syslog.log-1 has changed, I could parse it instead of syslog.log and keep continuous history.
Code:
# date -r /tmp/syslog.log-1
Wed Jun  1 14:58:47 DST 2022
Or perhaps a more useful format:
Code:
# date +%s -r /tmp/syslog.log-1
1654091927
 
Last edited:

Martinski

Regular Contributor
Very good, thanks.
Now I'm left with 1 problem.
If I try to regularly parse the content of the system log (via cron) and append it to a file, I end up having the same messages repeated several times (of course).
So far, the only solution I see is to wipe out all the text from syslog.log after parsing, so the next iteration is only fresh content. Yet, I find it convenient to be able to see the log on the webUI for some time.
One possible solution would be to write a unique "timestamp" into the syslog to indicate when a "snapshot" was taken. When parsing the contents of the snapshot, you look for the unique "timestamp" markers and only take the contents *between* the last 2 markers. If no "timestamp" markers are found, then you parse the entire file. Each time before taking a snapshot of the syslog, your write a unique "timestamp."

Roughly the code steps would be:
Bash:
MyUniqueTimeStamp="$(Custom Marker [$(date +%s)])"
logger -t "$MyUniqueTimeStamp" "Snapshot taken at this time."
echo "$MyUniqueTimeStamp" >> /PATH/TO/FILE/SysLogSnapshotMarkers.txt
cp -fp "/tmp/syslog.log" "/PATH/TO/FILE/syslog_copy.log"
## Now parse the contents of the "syslog_copy.log" file ##
Again, when parsing the contents of the "syslog_copy.log" file, only take the lines between the *previous* & the *last* "timestamp" markers which are now saved in the "SysLogSnapshotMarkers.txt" file. If no "timestamp" markers are found, you parse the whole file.

You'll need to handle the situation when the previous "timestamp" marker is now in the "syslog.log-1" file, and I'm sure there are some caveats/details that escape me at the moment (I haven't had my full cup of coffee yet ;)), but I think you're getting the idea.
 

ColinTaylor

Part of the Furniture
Following on from @Martinski's approach of using timestamps. To get around the problem of the syslog rotating you can use something like this to concatenate both syslog files:
Code:
cat /tmp/syslog.log-1 /tmp/syslog.log | sed -n "/$lasttimestamp/,$ p"
 

ColinTaylor

Part of the Furniture
@Oracle If you're only interested in making backup copies of the entire syslog every time it rotates, rather than filtering specific information, you could use the following script. Run it from cron every 5 minutes or so.
Code:
#!/bin/sh

syslogfile="/tmp/syslog.log-1"
backupdir="/mnt/ClickUSB1/ASUS/syslogs"

timestampfile="/tmp/syslog-backup.timestamp"
touch $timestampfile            # In case it doesn't exist

currenttimestamp="$(date +%s -r $syslogfile)"
previoustimestamp="$(cat $timestampfile)"
if [ "$currenttimestamp" != "$previoustimestamp" ]; then
    cp -p $syslogfile $backupdir/syslog.log-1-$(date +'%Y%m%d-%H%M%S' -r $syslogfile)
    echo $currenttimestamp > $timestampfile
fi

N.B. You'll probably get a duplicate file if you reboot the router as the router doesn't preserve the timestamp on the file.
 

Oracle

Regular Contributor
Appreciate all the nice hints and code snippets.

P. S. I put the code together in a script, set it to run every 1/2 hour from cron and observed the following:
1) The log grows relatively slow, so it's good enough to run every 2 or 3 hours or even less often.
2) The web IU of the router concatenates syslog.log-1 and syslog.log.

The code above provides excellent solution for long term system history. I'd vote for it to be included in the firmware. I modified it a little to suit my usage but it's simple, elegant and efficient.
 
Last edited:

Similar threads

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top