KSH : Display Wait message while processing a command - echo

I'm trying to display a message (with simple echo) like "Processing" which would go "Processing.", "Processing..", "Processing...", then go back the other way, and again, and again... until a command finish executing.
The command I'm trying to do that on is a simple git clone on a branch with 'quiet' parameter, looks like this :
git clone --quiet -b dev src_path dest_path >/dev/null
The idea is that, no matter the number of points after "Processing" (1, 2 or 3), it stops displaying when the process ends.
Don't know if there is a native way to do this, or if this is pretty hard to do, but I'm kind of new in KSH scripting so will not understand too complex stuff (plus i'm not english fluent)
Thanks for your answers !
Edit : Finally found a way to do it, maybe a little longer than what I was expecting for but since it doesn't seems to be a native way helping for this, that's pretty correct. Here's what I did (thanks to markp-fuso who helped with his keywords).
git clone --quiet -b dev src_path dest_path >/dev/null &
PROC_ID=$!
NB=0
WAY=1
while kill -0 "$PROC_ID" >/dev/null; do
if [ $WAY = 1 ]; then
if [ $NB = 2 ];then
WAY=0
fi
NB=$((NB+1))
else
if [ $NB = 2 ];then
WAY=1
fi
NB=$((NB-1))
fi
echo -ne "Processing"
i=1
while [ i -lt $((NB+1)) ]; do
echo -ne "."
i=$((i+1))
done
echo -ne " \r"
sleep 0.5
done
clear
echo -ne "Process complete.\n"
Note that I had to add a clear command at the end of the while loop because once the git clone is complete, the loop returns a warning saying the process doesn't exist (anymore). So I clear right after the warning displays to let it invisible for th user. If you find a way to catch it, you're welcome ! Really surprised that it displays even with the /dev/null statement.

You can adapt this strategy:
print -n "Processing"
while true; do
print -n "."
sleep 5
done

Related

zsh: Find out VCS of current directory

I'd like to create a zsh widget to perform common tasks of a version control systems with a single button. E.g. pressing F1 should call "svn status", if the current directory is part of a Subversion checkout. If it is in a git repository, it should call "git status -s".
Now, creating the widget is no big deal. But how do I determine which VCS is in the current directory?
I know about vcs_info and I use a lot. But I couldn't find any way to retrieve the most basic information, it provides. Any ideas?
What about testing the existence of the specific meta data directories?
if test -d CVS; then
# CVS
elif test -d .hg; then
# Mercurial
elif test -d .git; then
# Git
elif test -d .svn; then
# Subversion
else
# unknown
fi
Thanks to all for comments. My solution now looks like this:
vcs-status() {
setopt no_autopushd
cmd=""
cur_dir=`pwd`
while [[ `pwd` != "/" ]]; do
if [[ -d .svn ]]; then
cmd="svn status^M"
break
elif [[ -d .git ]]; then
cmd="git status -s^M"
break
fi
cd ..
done
cd $cur_dir
if [[ -n $cmd ]]; then
zle -U $cmd
fi
setopt autopushd
}
zle -N vcs-status
bindkey "\eOP" vcs-status
Suggestions to cool zsh'ish improvements are welcome :-)
I also implemented the suggestion of Thomas, using svn info and git rev-parse. But then I noticed a problem: If I have an SVN working copy checked out somewhere inside a GIT working copy (yes, this is necessary occationally), or vice versa, I would only find the first one I'm checking. With the solution above, I find the "inner-most", which is what I want. In fact, this is a problem that also has been annoying me about vcs_info for a while.

How is this bash script resulting in an infinite loop?

From some Googling (I'm no bash expert by any means) I was able to put together a bash script that allows me to run a test suite and output a status bar at the bottom while it runs. It typically takes about 10 hours, and the status bar tells me how many tests passed and how many failed.
It works great sometimes, however occasionally I will run into an infinite loop, which is bad (mmm-kay?). Here's the code I'm using:
#!/bin/bash
WHITE="\033[0m"
GREEN="\033[32m"
RED="\033[31m"
(run_test_suite 2>&1) | tee out.txt |
while IFS=read -r line;
do
printf "%$(tput cols)s\r" " ";
printf "%s\n" "$line";
printf "${WHITE}Passing Tests: ${GREEN}$(grep -c passed out.txt)\t" 2>&1;
printf "${WHITE}Failed Tests: ${RED}$( grep -c FAILED out.txt)${WHITE}\r" 2>&1;
done
What happens when I encounter the bug is I'll have an error message repeat infinitely, causing the log file (out.txt) to become some multi-megabyte monstrosity (I think it got into the GB's once). Here's an example error that repeats (with four lines of whitespace between each set):
warning caused by MY::Custom::Perl::Module::TEST_FUNCTION
print() on closed filehandle GEN3663 at /some/CPAN/Perl/Module.pm line 123.
I've tried taking out the 2>&1 redirect, and I've tried changing while IFS=read -r line; to while read -r line;, but I keep getting the infinite loop. What's stranger is this seems to happen most of the time, but there have been times I finish the long test suite without any problems.
EDIT:
The reason I'm writing this is to upgrade from a black & white test suite to a color-coded test suite (hence the ANSI codes). Previously, I would run the test suite using
run_test_suite > out.txt 2>&1 &
watch 'grep -c FAILED out.txt; grep -c passed out.txt; tail -20 out.txt'
Running it this way gets the same warning from Perl, but prints it to the file and moves on, rather than getting stuck in an infinite loop. Using watch, also prints stuff like [32m rather than actually rendering the text as green.
I was able to fix the perl errors and the bash script seems to work well now after a few modifications. However, it seems this would be a safer way to run the test suite in case something like that were to happen in the future:
#!/bin/bash
WHITE="\033[0m"
GREEN="\033[32m"
RED="\033[31m"
run_full_test > out.txt 2>&1 &
tail -f out.txt | while IFS= read line; do
printf "%$(tput cols)s\r" " ";
printf "%s\n" "$line";
printf "${WHITE}Passing Tests: ${GREEN}$(grep -c passed out.txt)\t" 2>&1;
printf "${WHITE}Failed Tests: ${RED}$( grep -c 'FAILED!!' out.txt)${WHITE}\r" 2>&1;
done
There are some downsides to this. Mainly, if I hit Ctrl-C to stop the test, it appears to have stopped, but really run_full_test is still running in the background and I need to remember to kill it manually. Also, when the test is finished tail -f is still running. In other words there are two processes running here and they are not in sync.
Here is the original script, slightly modified, which addresses those problems, but isn't foolproof (i.e. can get stuck in an infinite loop if run_full_test has issues):
#!/bin/bash
WHITE="\033[0m"
GREEN="\033[32m"
RED="\033[31m"
(run_full_test 2>&1) | tee out.txt | while IFS= read line; do
printf "%$(tput cols)s\r" " ";
printf "%s\n" "$line";
printf "${WHITE}Passing Tests: ${GREEN}$(grep -c passed out.txt)\t" 2>&1;
printf "${WHITE}Failed Tests: ${RED}$( grep -c 'FAILED!!' out.txt)${WHITE}\r" 2>&1;
done
The bug is in your script. That's not an IO error; that's an illegal argument error. That error happens when the variable you provide as a handle isn't a handle at all, or is one that you've closed.
Writing to a broken pipe results in the process being killed by SIGPIPE or in print returning false with $! set to EPIPE.

Get current playing file in MPlayer slave mode

Problem: I can't find any way to reliably get the current playing file in an MPlayer playlist.
Here is how far I have gotten. This working ash script monitors a text file with the path to the current playlist. When I update the file, the script closes the old instance of MPlayer and opens a new one with the new playlist:
# POLL PLAYLIST FILE FOR CHANGES
CURRENTPLAYLISTPATH=/home/tc/currentplaylist
INFIFO=/tmp/mplayer-in
CURRENTPLAYLIST="NEVERMATCHAPLAYLIST"
FIRSTRUN=1
while [ 1 ];
do
# CHECK FOR NEW PLAYLIST
NEWPLAYLIST=$(head -n 1 $CURRENTPLAYLISTPATH)
if [[ "$NEWPLAYLIST" != "$CURRENTPLAYLIST" ]]; then
if [ "$FIRSTRUN" == 0 ]; then
echo "quit" > "$INFIFO"
fi
# CREATE NAMED PIPE, IF NEEDED
trap "rm -f $INFIFO" EXIT
if [ ! -p $INFIFO ]; then
mkfifo $INFIFO
fi
# START MPLAYER
mplayer -fixed-vo -nolirc -vc ffmpeg12vdpau,ffh264vdpau, -playlist $NEWPLAYLIST -loop 0 -geometry 1696x954 -slave -idle -input file=$INFIFO -quiet -msglevel all=0 -identify | tee -a /home/tc/mplayer.log &
CURRENTPLAYLIST=$NEWPLAYLIST
FIRSTRUN=0
fi
sleep 5;
done
My original plan was just to use the "-identify" flag and parse the log file. This actually works really well up until I need to truncate the log file to keep it from getting too large. As soon as my truncating script is run, MPlayer stops writing to the log file:
FILENAME=/home/tc/mplayer.log
MAXCOUNT=100
if [ -f "$FILENAME" ]; then
LINECOUNT=`wc -l "$FILENAME" | awk '{print $1}'`
if [ "$LINECOUNT" -gt "$MAXCOUNT" ]; then
REMOVECOUNT=`expr $LINECOUNT - $MAXCOUNT`
sed -i 1,"$REMOVECOUNT"d "$FILENAME"
fi
fi
I have searched and searched but have been unable to find any other way of getting the current playing file that works.
I have tried piping the output to another named pipe and then monitoring it, but only works for a few seconds, then MPlayer completely freezes.
I have also tried using bash (instead of ash) and piping the output to a function like the following, but get the same freezing problem:
function parseOutput()
{
while read LINE
do
echo "get_file_name" > /tmp/mplayer-in
if [[ "$LINE" == *ANS_FILENAME* ]]
then
echo ${LINE##ANS_FILENAME=} > "$CURRENTFILEPATH"
fi
sleep 1
done
}
# START MPLAYER
mplayer -fixed-vo -nolirc -vc ffmpeg12vdpau,ffh264vdpau, -playlist $NEWPLAYLIST -loop 0 -geometry 1696x954 -slave -idle -input file=/tmp/mplayer-in -quiet | parseOutput &
I suspect I am missing something very obvious here, so any help, ideas, points in the right direction would be greatly appreciated.
fodder
Alright then, so I'll post mine too.
Give this one a try (assuming there is only one instance running, like on fodder's machine):
basename "$(readlink /proc/$(pidof mplayer)/fd/* | grep -v '\(/dev/\|pipe:\|socket:\)')"
This is probably the safer way, since the file descriptors might not always be in the same order on all systems.
However, this can be shortened, with a little risk:
basename "$(readlink /proc/$(pidof mplayer)/fd/*)" | head -1
You might probably like to install this, too:
http://mplayer-tools.sourceforge.net/
Well, I gave up on getting the track from MPlayer itself.
My 'solution' is probably too hackish, but works for my needs since I know my machine will only ever have one instance of MPlayer running:
lsof -p $(pidof mplayer) | grep -o "/path/to/my/assets/.*"
If anyone has a better option I'm certainly still interested in doing this the right way, I just couldn't make any of the methods work.
fodder
You can use the run command.
Put this in ~/.mplayer/input.conf:
DEL run "echo ${filename} ${stream_pos} >> /home/knarf/out"
Now if you press the delete key while playing a file it will do what you expect i.e. append the current file playing and the position in the stream to the ~/out file. You can replace echo with your program.
See slave mod docs for more info (Ctrl-F somevar).
About getting properties from MPlayer
I have used a non-elegant solution, but it is working for me.
stdbuf -oL mplayer --slave --input=file=$FIFO awesome_awesome.mp3 |
{
while IFS= read -r line
do
if [[ "${line}" == ANS_* ]]; then
echo "${line#*=}" > ${line%=*} # echo property_value > property_name
fi
done
} &
mplayer_pid=&!
read filename < ./ANS_FILENAME
read timeLength < ./ANS_LENGTH
echo ($timeLength) $filename
and so on..
It is in another proccess, that's why I've used files to bring properties
'stdbuf' is for not to miss anything
I started putting together a bash library to handle tasks like this. Basically, you can accomplish this by dumping the mplayer output to a file. Then you grep that dump for "Playing " and take the last result with tail. This should give you the name of the file that's currently playing or that last finished playing.
Take a look at my bash code. You'll want to modify the playMediaFile function to your needs, but the getMediaFileName function should do exactly what you're asking. You'll find the code on my github.

How can I make a shell script indicate that it was successful?

If I have a basic .sh file containing the following script code:
#!/bin/sh
rm -rf "MyFolder"
How do I make this running script file display results to the terminal that will indicate if the directory removal was successful?
You don't really need to make it say it was successful. You could have it say something only on error ✖, and then silence means success ✔.
That's how the Unix philosophy works:
The rule of silence, also referred to as the silence is golden rule, is an important part of the Unix philosophy that states that when a program has nothing surprising, interesting or useful to say, it should say nothing. It means that well-behaved programs should treat their users' attention and concentration as being valuable and thus perform their tasks as unobtrusively as possible. That is, silence in itself is a virtue. http://www.linfo.org/rule_of_silence.html
That's the way rm itself behaves.
If you are asking about the general case, as suggested by your question's title, you can run your script with sh -x scriptname to see what it's doing. It's also quite common to write diagnostic output into the script itself, and control it with an option.
#!/bin/sh
verbose=false
case $1 in -v | --verbose )
verbose=true
shift ;;
esac
say () {
$verbose || return
echo "$0: $#" >&2
}
say "Removing $dir ..."
rm -rf "$dir" || say "Failed."
If you run this script without any options, it will run silently, like a well-behaved Unix utility should. If you run it with the -v option, it will print some diagnostics to standard error.
rm -rf "My Folder" && echo "Done" || echo "Error!"
You can read more on creating a sequence of pipelines in bash manual
In the bash (and other similar shells) the ? environment variable gives you the exit code of the last executed command. So you can do:
#!/bin/sh
rm -rf "My Folder"
echo $?
UPDATE
If once the rm command has been executed the directory doesn't exist (because it has been successfully removed or because it didn't exist when the command was executed) the script will print 0. If the directory exists (which will mean that the command has been unable to remove it) then the script will print an exit code other than 0. If I understand properly the question this is exactly the requested behavior. If it is not, please correct me.
The previous answers was wrong : rm don't exit with error code > 0 when the dir isn't present.
Instead, I recommend to use :
dir='/path/to/dir'
if [[ -d $dir ]]; then
rm -rf "$dir"
fi
If you want rm to return a status, remove -f flag.
Example on Linux Mint (the dir doesn't exists):
$ rm -rf /tmp/sdfghjklm
$ echo $?
0
$ rm -r /tmp/sdfghjklm
$ echo $?
1

Convert Bash script to Perl/VBS/any other windows compatible language [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I got a bash script that was made for transferring files from a Sandbox to a host.
The files in the sandboxdirectory get transferred only if they are younger, meaning they have been "touched" before. Unfortunately, cygwin is causing trouble under windows so I need the script in another language or I need something that works like cygwin under windows.
The script is just about 20 lines, but i don't have any clue how to convert it to another language(especially commands like touch, make, gcc, getopts, set -e)
I'd be happy if someone finds this easy to do and converts it:
# EXITING SCRIPT IF ERROR OCCURS
set -e
FORCE=false
JUSTPRINT=
# if parameter -f is given, force to transfer all files(no matter if new or not)
# if -n is given checking files
while getopts fn opt 2>/dev/null
do
case $opt in
f) FORCE=true ;;
n) JUSTPRINT="-n" ;;
?) ;;
esac
done
# deleting parsed options from command line
shift `expr $OPTIND - 1`
# refresh files that came with -f
if [ \( $FORCE = true \) -a \( $# -gt 0 \) ]
then
touch -c $#
fi
# Targets (dummy files for timestamp)
TARGETS=`for filename
do
if [ -f $filename ]
then
echo "../transport_dummies/\`basename $filename\`.dum"
else
echo "$filename"
fi
done`
# call script directory
echo $0
cd `dirname $0`
# creating sysfilterL.exe
if [ ! -f sysfilterL ]
then
echo "sysfilterL is created."
gcc sysfilter.c -o sysfilterL
fi
# Call Transport-Makefile with target
if [ $# -gt 0 ]
then
make --warn-undefined-variables $JUSTPRINT -f transportDE.mk reset $TARGETS
send_queueed
else
make --warn-undefined-variables $JUSTPRINT -f transportDE.mk
fi
You can convert the shell script to a batch file, which is covered here: How do I convert a bash shell script to a .bat file?
Also here is a list of corresponding commands in bash and batch: http://tldp.org/LDP/abs/html/dosbatch.html