for what reason do i keep getting "bsd syntax error" when i run ps -f in shell script? - linux

so, i'm a beginner to Shell, i need to write a script that, given a numeric argument, will display info about the processes with the entered numbers (by user ofc), given a non numeric argument, if it's "--help" it will display help (which i really don't know how to do), and if it's something else, it gives info about processes having that argument as names ( for ex, "./script bash" will display info about the bash process) , here is what i've done so far:
#!/bin/sh
case $arg in
$num )
a=""
for arg in $#
do
a="${a} $arg"
done
printf "$(ps -f ${a})\n"
;;
*)
p=$(pidof ${arg})
printf "$(ps -f ${p})"
;;
esac
so, the numeric argument part works, but the other one doesn't, whenever i enter a non numeric name i get that "BSD syntax" error message and i really don't know what to do.
thank you to everyone willing to help me out.

Related

About saving value of expression in shell programming

I'm just so stressed struggling about this simple grammar.
I learned in text;
To store value in shell programming, we use value=$(expression).
So I made following script
#!/bin/bash
address=$1
echo $address
value=$(test -d $address)
echo $value
This is a script to find if my input(directory) exists and accessible.
Address shows me the input but $value shows nothing.
At least I expected 0 or non-zero but it didn't!
Can anybody teach me how to save the result of test?
test has no output, but the result of the last command is saved as $?, so you could either -
value=$(test -d $address; echo $?)
or just skip saving it and use the test.
if [ -d "$address" ]
then ...

Defining flag parameters in bash

I wrote bash script, in which I included some logging, to see what is going on in each step of exectuion.
Now, I can split those logs in debuggin info and user info (that something has completed, etc.). So I'd like to have some flag parameter, like --verbose, which I saw in some other bash functions to enable full logging and usage was like:
some_function --verbose
or
some_function -v
I call it flag parameters and don't know what's the right name, thus I can't find anything useful.
How to define such parameters for bash script?
Case suits better for this
while [[ "$#" ]]; do
case "$1" in
-v|--verbose) verbose="true";;
esac
shift
done
Same can be done in function, but note that in this case it'll process parameters passed to function some_function -v.
some_function () {
while [[ "$#" ]]; do
case "$1" in
-v|--verbose) verbose="true";;
esac
shift
done
}
Then somewhere in script you can check if verbose is set
[[ "$verbose" ]] && echo "verbose mode" || echo "silent mode"
For now, I used workaround and take it as normal positional parameter (as $n). To be exact, I have list of four parameters, so I collect this flag like this:
verbose=$4
if [ ! "$verbose" == "--verbose" ]; then
verbose=""
fi
So, if parameter is not matching a flag, then I leave it empty and if I want to use it, I just compare it against empty string.
There's one big disadvantage for me though: it has to be at 4th position in parameters list.

Bash how check if an argument is a sed patterns?

I'm working on a bash script that should receive many arguments. those arguments could be simple like:
Myscript [-r] [-l|-u] <dir/file names...>
or it could be just a sed patterns given instead of a simple arguments like:
Myscript <sed pattern> <dir/file names...>
So my question is how to check if the arguments given is a sed patterns and not directory path or filename?
I have done something but it doesn't work for a long path (dir1/dir2/dir)
while [[ $# > 0 ]]
do
key="$1"
case $key in
-ru|-ur)
config_recusive
config_upper
shift
;;
-rl|-lr)
config_recusive
config_lower
shift
;;
-r)
config_recusive
shift
;;
-l)
config_lower
shift
;;
-u)
config_upper
shift
;;
*)
check="^.*/.*/.*$"
if [[ $key =~ $check ]] ; then
config_sed_pattern
else
TARGET=$key
fi
shift
;;
esac
done
To be more clear, here is an example of my problem when I'm trying to run the script like that:
./myscript -u tmp/users/regions
its being confused taking the path (tmp/users/regions) as a sed patterns.
hope that I was clear enough.
waiting for your help :)
thanks
i think you could use try run that script on something
echo a | sed "$pattern" >/dev/null 2>/dev/null
and then check the $?
if [ $? != 0 ]; then # means sed failed
#...
but maybe sed will think it will be its argument too.
btw, handle arguments using getopt will make things easier.
i don't think the way you design argument format is good. maybe you think making arguments in different forms could make your program looks dynamic and awesome. but now you are trying to solve a problem have nothing to do with your serious business and wasting your own time and ours. that's not good. it's better to make things stupid and clear.
in your case, maybe you can add another argument to show it's a sed expression that follows.
YourScript -e <sed expr> <others>
and in such a way, you will have idea about what you have done two weeks later.

Script parameters in Bash

I'm trying to make a shell script which should be used like this:
ocrscript.sh -from /home/kristoffer/test.png -to /home/kristoffer/test.txt
The script will then ocr convert the image file to a text file. Here is what I have come up with so far:
#!/bin/bash
export HOME=/home/kristoffer
/usr/local/bin/abbyyocr9 -rl Swedish -if ???fromvalue??? -of ???tovalue??? 2>&1
But I don't know how to get the -from and -to values. Any ideas on how to do it?
The arguments that you provide to a bashscript will appear in the variables $1 and $2 and $3 where the number refers to the argument. $0 is the command itself.
The arguments are seperated by spaces, so if you would provide the -from and -to in the command, they will end up in these variables too, so for this:
./ocrscript.sh -from /home/kristoffer/test.png -to /home/kristoffer/test.txt
You'll get:
$0 # ocrscript.sh
$1 # -from
$2 # /home/kristoffer/test.png
$3 # -to
$4 # /home/kristoffer/test.txt
It might be easier to omit the -from and the -to, like:
ocrscript.sh /home/kristoffer/test.png /home/kristoffer/test.txt
Then you'll have:
$1 # /home/kristoffer/test.png
$2 # /home/kristoffer/test.txt
The downside is that you'll have to supply it in the right order. There are libraries that can make it easier to parse named arguments on the command line, but usually for simple shell scripts you should just use the easy way, if it's no problem.
Then you can do:
/usr/local/bin/abbyyocr9 -rl Swedish -if "$1" -of "$2" 2>&1
The double quotes around the $1 and the $2 are not always necessary but are adviced, because some strings won't work if you don't put them between double quotes.
If you're not completely attached to using "from" and "to" as your option names, it's fairly easy to implement this using getopts:
while getopts f:t: opts; do
case ${opts} in
f) FROM_VAL=${OPTARG} ;;
t) TO_VAL=${OPTARG} ;;
esac
done
getopts is a program that processes command line arguments and conveniently parses them for you.
f:t: specifies that you're expecting 2 parameters that contain values (indicated by the colon). Something like f:t:v says that -v will only be interpreted as a flag.
opts is where the current parameter is stored. The case statement is where you will process this.
${OPTARG} contains the value following the parameter. ${FROM_VAL} for example will get the value /home/kristoffer/test.png if you ran your script like:
ocrscript.sh -f /home/kristoffer/test.png -t /home/kristoffer/test.txt
As the others are suggesting, if this is your first time writing bash scripts you should really read up on some basics. This was just a quick tutorial on how getopts works.
Use the variables "$1", "$2", "$3" and so on to access arguments. To access all of them you can use "$#", or to get the count of arguments $# (might be useful to check for too few or too many arguments).
I needed to make sure that my scripts are entirely portable between various machines, shells and even cygwin versions. Further, my colleagues who were the ones I had to write the scripts for, are programmers, so I ended up using this:
for ((i=1;i<=$#;i++));
do
if [ ${!i} = "-s" ]
then ((i++))
var1=${!i};
elif [ ${!i} = "-log" ];
then ((i++))
logFile=${!i};
elif [ ${!i} = "-x" ];
then ((i++))
var2=${!i};
elif [ ${!i} = "-p" ];
then ((i++))
var3=${!i};
elif [ ${!i} = "-b" ];
then ((i++))
var4=${!i};
elif [ ${!i} = "-l" ];
then ((i++))
var5=${!i};
elif [ ${!i} = "-a" ];
then ((i++))
var6=${!i};
fi
done;
Rationale: I included a launcher.sh script as well, since the whole operation had several steps which were quasi independent on each other (I'm saying "quasi", because even though each script could be run on its own, they were usually all run together), and in two days I found out, that about half of my colleagues, being programmers and all, were too good to be using the launcher file, follow the "usage", or read the HELP which was displayed every time they did something wrong and they were making a mess of the whole thing, running scripts with arguments in the wrong order and complaining that the scripts didn't work properly. Being the choleric I am I decided to overhaul all my scripts to make sure that they are colleague-proof. The code segment above was the first thing.
In bash $1 is the first argument passed to the script, $2 second and so on
/usr/local/bin/abbyyocr9 -rl Swedish -if "$1" -of "$2" 2>&1
So you can use:
./your_script.sh some_source_file.png destination_file.txt
Explanation on double quotes;
consider three scripts:
# foo.sh
bash bar.sh $1
# cat foo2.sh
bash bar.sh "$1"
# bar.sh
echo "1-$1" "2-$2"
Now invoke:
$ bash foo.sh "a b"
1-a 2-b
$ bash foo2.sh "a b"
1-a b 2-
When you invoke foo.sh "a b" then it invokes bar.sh a b (two arguments), and with foo2.sh "a b" it invokes bar.sh "a b" (1 argument). Always have in mind how parameters are passed and expaned in bash, it will save you a lot of headache.

I keep getting a 'while syntax' error on the output of the at job in unix and I have no idea why

#!/usr/dt/bin/dtksh
while getopts w:m: option
do
case $option in
w) wflag=1
wval="$OPTARG";;
m) mflag=1
mval="$OPTARG";;
?) printf 'BAD\n' $0
exit 2;;
esac
done
if [ ! -z "$wflag" ]; then
printf "W and -w arg is $wval\n"
fi
if [ ! -z "$mflag" ]; then
printf "M and -m arg is $mval\n"
fi
shift $(($OPTIND - 1))
printf "Remaining arguments are: $* \n"
at $wval <<ENDMARKER
echo $* >> Search_List
tr " " "\n" <Search_List >Usr_List
while true; do
if [ -s Usr_List ]; then
for i in $(cat Usr_List); do
if finger -m | grep $i; then
echo '$i is online' | elm user
sed '/$i/d' <Usr_List >tmplist
mv tmplist Usr_List
fi
done
else
break
fi
done
ENDMARKER
Essentially I want to keep searching through until it is empty. Each time an element of the list is found, it is deleted. Once the list is empty quit.
There are no error messages when I first run the command, it only shows up in an email containing the output of the at job.
Thanks in advance for any advice
EDIT: The script uses getopts and takes one argument for -w and one for -m, the w value is set as the time for the at job, the m still has to be used. Any arguments after the one for m are sent to a file called Search_List, Search_List is edited and saved as Usr_List. Then in the while loop, while Usr_List is not empty, the script checks the results of finger -m against the names in Usr_List. If a name is found, it is removed from Usr_List. Once Usr_List is empty, the program should stop.
elm is a way to send an email, so elm user sends an email to user.
The error is :
while: Expression syntax
at uses /bin/sh by default.
at now <<ENDMARKER
<code here>
ENDMARKER
All of this executes under /bin/sh, which on some systems can be Bourne Shell (Solaris for example).
You need to figure out what /bin/sh is for your system, then modify things accordingly. Plus, read the gurantees about what is and what is not in your "at" environment. I think the problem lies there. You have both UNIX and linux tags. So I cannot give a lot more help than that.
You can enable logging -- the way YOU need it -- of the at code chunk:
exec 2&>1 > /tmp/somefile.log
Then write debugging messages to stdout or stderr.
Your HEREDOC is being interpolated. Try quoting the delimiter:
at $wval << 'ENDMARKER'
Although ( I haven't looked closely) it appears that you want some interpolation. But you definitely do not want it on the line in which you reference $i, so quote that $ if you do not quote the entire heredoc:
if finger -m | grep \$i; then
You need to pass the -k option to at:
...
at -k $wval <<ENDMARKER
...
at is otherwise defaulting to your login shell which is csh or one of its derivatives.
It turns out that the while command and the if command needed to be combined.
while [[ -s Usr_List ]]; do
......
done

Resources