Sending the output of a while loop to a bash function - bash

I've created a .bashrc file where I have two functions. One loops through the lines of a file in a while loop. I'm attempting to save the content of the lines if they match certain conditions and then pass all three matches to a second function that will then echo them. However, I've tried exporting variables and I've also tried piping to the second function, but neither works. Piping also acts very strangely as I'll try to illustrate in my code example.
readAndPipe() {
while read -r line || [[ -n "$line" ]]; do
(
if [[ $line == FIRSTNAME=BOB ]]; then
echo $line;
fi;
if [[ $line == LASTNAME=SMITH ]]; then
echo $line;
fi;
if [[ $line == BIRTHMONTH=AUGUST ]]; then
echo $line;
fi;
); done < "file.txt" | printArguments $1 #pass the original command line argument;
}
printArguments() {
#This is where the weirdness happens
echo $# #Prints: only the original command line argument
echo $# #Prints: 1
echo $2 $3 $4 #Prints nothing
varName=$(cat $2 $3 $4)
echo $varName #Prints: FIRSTNAME=BOB
# LASTNAME=SMITH
# BIRTHMONTH=AUGUST
cat $2 $3 $4 #Prints nothing
echo $(cat $2 $3 $4) #Prints nothing
cat $2 $3 $4 | tr "\n" '' #Prints tr: empty string2
}
Obviously I'm not a bash expert so I'm sure there's a lot of mistakes here, but what I'm wondering is
What are these seemingly magical $2 $3 $4 arguments that are not
printed by echo but can be used by cat exactly once.
What is the
correct way to save content during a while loop and pass it to
another function so that I can echo it?

$#, $*, $1, $2, etc are the arguments that are passed to the function. For example, in myfunc foo bar baz, we have $1 == foo, $2 == bar and $3 == baz.
When you pipe data to your function, you have to retrieve it from from stdin:
myfunc() {
data=$(cat)
echo "I received: >$data<"
}
for n in {1..5}; do echo "x=$n"; done | myfunc
produces
I received: >x=1
x=2
x=3
x=4
x=5<
varName=$(cat $2 $3 $4) works because $2 $3 and $4 are empty, so the shell sees this:
varName=$(cat )
The reason cat "only works once" is because you are consuming a stream. Once you consume it, it's gone. "you can't eat your cake and have it too."
The printArguments function can use the readarray command to grab the incoming lines into an array, instead of using cat to grab all the incoming text into a variable:
printArguments() {
readarray -t lines
echo "I have ${#lines[#]} lines"
echo "they are:"
printf ">>%s\n" "${lines[#]}"
}
{ echo foo; echo bar; echo baz; } | printArguments
outputs
I have 3 lines
they are:
>>foo
>>bar
>>baz
Learn more by typing help readarray at an interactive bash prompt.

Imagine a script:
func() {
echo $# # will print 2, func were executed with 2 arguments
echo "$#" # will print `arg1 arg2`, ie. the function arguments
in=$(cat) # will pass stdin to `cat` function and save cat's stdout into a variable
echo "$in" # will print `1 2 3`
}
echo 1 2 3 | func arg1 arg2
# ^^^^^^ function `func` arguments
# ^ passed one command stdout to other command stdin
# ^^^ outputs `1 2 3` on process stdout
cat invoked without any arguments, reads stdin and outputs it on stdout.
Invoking a command in command substitution passes stdin along (ie. in=$(cat) will read stdin as normal cat just saves the output (ie. the cat's stdout) into a variable)
To your script:
readAndPipe() {
# the while read line does not matter, but it outputs something on stdout
while read -r line || [[ -n "$line" ]]; do
echo print something
# the content of `file.txt` is passed as while read input
done < "file.txt" | printArguments $1 # the `print something` (the while loop stdout output) is passed as stdin to the printArguments function
}
printArguments() {
# here $# is equal to 1
# $1 is equal to passed $1 (unless expanded, will get to that)
# $2 $3 $4 expand to nothing
varName=$(cat $2 $3 $4) # this executes varName=$(cat) as $2 $3 $4 expand to nothing
# now after this point stdin has been read (it can be read once, it's a stream or pipe
# is you execute `cat` again it will block (waiting for more input) or fail (will receive EOF - end of file)
echo $varName #Prints: `print something` as it was passed on stdin to this function
}
If the file file.txt contains only just:
FIRSTNAME=BOB
LASTNAME=SMITH
BIRTHMONTH=AUGUST
you can just load the file . file.txt or source file.txt. This will "load" the file, ie. make it part of your script, syntax is bash. So you can:
. file.txt
echo "$FIRSTNAME"
echo "$LASTNAME"
echo "$BIRTHMONTH"
This is a common way of creating configuration files in /etc/ and then they are loaded by scripts. That's why in many /etc/ files comments start with #.
Notes:
Always enclose your variables. echo "$1" printArguments "$1" echo "$#" echo "$#" cat "$2" "$3" "$4" [ "$line" == ... ], a good read is here
Remove newlines with tr -d '\n'
A ( ) creates a subshell, which creates a new shell which has new variables and does not share variable with the parent, see here.

Related

Can't add a new element to an array in bash [duplicate]

In the following program, if I set the variable $foo to the value 1 inside the first if statement, it works in the sense that its value is remembered after the if statement. However, when I set the same variable to the value 2 inside an if which is inside a while statement, it's forgotten after the while loop. It's behaving like I'm using some sort of copy of the variable $foo inside the while loop and I am modifying only that particular copy. Here's a complete test program:
#!/bin/bash
set -e
set -u
foo=0
bar="hello"
if [[ "$bar" == "hello" ]]
then
foo=1
echo "Setting \$foo to 1: $foo"
fi
echo "Variable \$foo after if statement: $foo"
lines="first line\nsecond line\nthird line"
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done
echo "Variable \$foo after while loop: $foo"
# Output:
# $ ./testbash.sh
# Setting $foo to 1: 1
# Variable $foo after if statement: 1
# Value of $foo in while loop body: 1
# Variable $foo updated to 2 inside if inside while loop
# Value of $foo in while loop body: 2
# Value of $foo in while loop body: 2
# Variable $foo after while loop: 1
# bash --version
# GNU bash, version 4.1.10(4)-release (i686-pc-cygwin)
echo -e $lines | while read line
...
done
The while loop is executed in a subshell. So any changes you do to the variable will not be available once the subshell exits.
Instead you can use a here string to re-write the while loop to be in the main shell process; only echo -e $lines will run in a subshell:
while read line
do
if [[ "$line" == "second line" ]]
then
foo=2
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo "Value of \$foo in while loop body: $foo"
done <<< "$(echo -e "$lines")"
You can get rid of the rather ugly echo in the here-string above by expanding the backslash sequences immediately when assigning lines. The $'...' form of quoting can be used there:
lines=$'first line\nsecond line\nthird line'
while read line; do
...
done <<< "$lines"
UPDATED#2
Explanation is in Blue Moons's answer.
Alternative solutions:
Eliminate echo
while read line; do
...
done <<EOT
first line
second line
third line
EOT
Add the echo inside the here-is-the-document
while read line; do
...
done <<EOT
$(echo -e $lines)
EOT
Run echo in background:
coproc echo -e $lines
while read -u ${COPROC[0]} line; do
...
done
Redirect to a file handle explicitly (Mind the space in < <!):
exec 3< <(echo -e $lines)
while read -u 3 line; do
...
done
Or just redirect to the stdin:
while read line; do
...
done < <(echo -e $lines)
And one for chepner (eliminating echo):
arr=("first line" "second line" "third line");
for((i=0;i<${#arr[*]};++i)) { line=${arr[i]};
...
}
Variable $lines can be converted to an array without starting a new sub-shell. The characters \ and n has to be converted to some character (e.g. a real new line character) and use the IFS (Internal Field Separator) variable to split the string into array elements. This can be done like:
lines="first line\nsecond line\nthird line"
echo "$lines"
OIFS="$IFS"
IFS=$'\n' arr=(${lines//\\n/$'\n'}) # Conversion
IFS="$OIFS"
echo "${arr[#]}", Length: ${#arr[*]}
set|grep ^arr
Result is
first line\nsecond line\nthird line
first line second line third line, Length: 3
arr=([0]="first line" [1]="second line" [2]="third line")
You are asking this bash FAQ. The answer also describes the general case of variables set in subshells created by pipes:
E4) If I pipe the output of a command into read variable, why
doesn't the output show up in $variable when the read command finishes?
This has to do with the parent-child relationship between Unix
processes. It affects all commands run in pipelines, not just
simple calls to read. For example, piping a command's output
into a while loop that repeatedly calls read will result in
the same behavior.
Each element of a pipeline, even a builtin or shell function,
runs in a separate process, a child of the shell running the
pipeline. A subprocess cannot affect its parent's environment.
When the read command sets the variable to the input, that
variable is set only in the subshell, not the parent shell. When
the subshell exits, the value of the variable is lost.
Many pipelines that end with read variable can be converted
into command substitutions, which will capture the output of
a specified command. The output can then be assigned to a
variable:
grep ^gnu /usr/lib/news/active | wc -l | read ngroup
can be converted into
ngroup=$(grep ^gnu /usr/lib/news/active | wc -l)
This does not, unfortunately, work to split the text among
multiple variables, as read does when given multiple variable
arguments. If you need to do this, you can either use the
command substitution above to read the output into a variable
and chop up the variable using the bash pattern removal
expansion operators or use some variant of the following
approach.
Say /usr/local/bin/ipaddr is the following shell script:
#! /bin/sh
host `hostname` | awk '/address/ {print $NF}'
Instead of using
/usr/local/bin/ipaddr | read A B C D
to break the local machine's IP address into separate octets, use
OIFS="$IFS"
IFS=.
set -- $(/usr/local/bin/ipaddr)
IFS="$OIFS"
A="$1" B="$2" C="$3" D="$4"
Beware, however, that this will change the shell's positional
parameters. If you need them, you should save them before doing
this.
This is the general approach -- in most cases you will not need to
set $IFS to a different value.
Some other user-supplied alternatives include:
read A B C D << HERE
$(IFS=.; echo $(/usr/local/bin/ipaddr))
HERE
and, where process substitution is available,
read A B C D < <(IFS=.; echo $(/usr/local/bin/ipaddr))
Hmmm... I would almost swear that this worked for the original Bourne shell, but don't have access to a running copy just now to check.
There is, however, a very trivial workaround to the problem.
Change the first line of the script from:
#!/bin/bash
to
#!/bin/ksh
Et voila! A read at the end of a pipeline works just fine, assuming you have the Korn shell installed.
This is an interesting question and touches on a very basic concept in Bourne shell and subshell. Here I provide a solution that is different from the previous solutions by doing some kind of filtering. I will give an example that may be useful in real life. This is a fragment for checking that downloaded files conform to a known checksum. The checksum file look like the following (Showing just 3 lines):
49174 36326 dna_align_feature.txt.gz
54757 1 dna.txt.gz
55409 9971 exon_transcript.txt.gz
The shell script:
#!/bin/sh
.....
failcnt=0 # this variable is only valid in the parent shell
#variable xx captures all the outputs from the while loop
xx=$(cat ${checkfile} | while read -r line; do
num1=$(echo $line | awk '{print $1}')
num2=$(echo $line | awk '{print $2}')
fname=$(echo $line | awk '{print $3}')
if [ -f "$fname" ]; then
res=$(sum $fname)
filegood=$(sum $fname | awk -v na=$num1 -v nb=$num2 -v fn=$fname '{ if (na == $1 && nb == $2) { print "TRUE"; } else { print "FALSE"; }}')
if [ "$filegood" = "FALSE" ]; then
failcnt=$(expr $failcnt + 1) # only in subshell
echo "$fname BAD $failcnt"
fi
fi
done | tail -1) # I am only interested in the final result
# you can capture a whole bunch of texts and do further filtering
failcnt=${xx#* BAD } # I am only interested in the number
# this variable is in the parent shell
echo failcnt $failcnt
if [ $failcnt -gt 0 ]; then
echo $failcnt files failed
else
echo download successful
fi
The parent and subshell communicate through the echo command. You can pick some easy to parse text for the parent shell. This method does not break your normal way of thinking, just that you have to do some post processing. You can use grep, sed, awk, and more for doing so.
I use stderr to store within a loop, and read from it outside.
Here var i is initially set and read inside the loop as 1.
# reading lines of content from 2 files concatenated
# inside loop: write value of var i to stderr (before iteration)
# outside: read var i from stderr, has last iterative value
f=/tmp/file1
g=/tmp/file2
i=1
cat $f $g | \
while read -r s;
do
echo $s > /dev/null; # some work
echo $i > 2
let i++
done;
read -r i < 2
echo $i
Or use the heredoc method to reduce the amount of code in a subshell.
Note the iterative i value can be read outside the while loop.
i=1
while read -r s;
do
echo $s > /dev/null
let i++
done <<EOT
$(cat $f $g)
EOT
let i--
echo $i
How about a very simple method
+call your while loop in a function
- set your value inside (nonsense, but shows the example)
- return your value inside
+capture your value outside
+set outside
+display outside
#!/bin/bash
# set -e
# set -u
# No idea why you need this, not using here
foo=0
bar="hello"
if [[ "$bar" == "hello" ]]
then
foo=1
echo "Setting \$foo to $foo"
fi
echo "Variable \$foo after if statement: $foo"
lines="first line\nsecond line\nthird line"
function my_while_loop
{
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2; return 2;
echo "Variable \$foo updated to $foo inside if inside while loop"
fi
echo -e $lines | while read line
do
if [[ "$line" == "second line" ]]
then
foo=2;
echo "Variable \$foo updated to $foo inside if inside while loop"
return 2;
fi
# Code below won't be executed since we returned from function in 'if' statement
# We aready reported the $foo var beint set to 2 anyway
echo "Value of \$foo in while loop body: $foo"
done
}
my_while_loop; foo="$?"
echo "Variable \$foo after while loop: $foo"
Output:
Setting $foo 1
Variable $foo after if statement: 1
Value of $foo in while loop body: 1
Variable $foo after while loop: 2
bash --version
GNU bash, version 3.2.51(1)-release (x86_64-apple-darwin13)
Copyright (C) 2007 Free Software Foundation, Inc.
Though this is an old question and asked several times, here's what I'm doing after hours fidgeting with here strings, and the only option that worked for me is to store the value in a file during while loop sub-shells and then retrieve it. Simple.
Use echo statement to store and cat statement to retrieve. And the bash user must chown the directory or have read-write chmod access.
#write to file
echo "1" > foo.txt
while condition; do
if (condition); then
#write again to file
echo "2" > foo.txt
fi
done
#read from file
echo "Value of \$foo in while loop body: $(cat foo.txt)"

Get number of line of word number X in file

Need to make a shell script that splits every csv file that uses \n as separator, the limit per file is the number of words and
I can't cut the line in half.
Finished script with the help of a wizard!
Example:
sh SliceByWords.sh 1000 .
Slices every file by 1000 words and put every part into subfolder
function has_number_number_of_words {
re='^[0-9]+$'
if ! [[ $1 =~ $re ]] ; then
echo "error: Not a number, please run the command with the number of words per file" >&2; exit 1
fi
}
#MAIN
has_number_number_of_words $1
declare -i WORDLIMIT=$1 # N of lines to part each file
subdir="Result"
mkdir $subdir
format=*.csv
for name in $format; do mv "$name" "${name// /___}"; done
for i in $format;
do
if [[ "$i" == "$format" ]]
then
echo "No Files"
else
( locali=$(echo $i | awk '{gsub(/ /,"\\ ");print}');
localword=$i;
FILENAMEWITHOUTEXTENSION="${localword%.*}" ;
subnoext=$subdir"/"$FILENAMEWITHOUTEXTENSION;
echo Processing file "$FILENAMEWITHOUTEXTENSION";
awk -v NOEXT=$subnoext -v wl=$WORDLIMIT -F" " 'BEGIN{fn=1}{c+=NF}{sv=NOEXT"_snd_"fn".csv";print $0>sv;}c>wl{c=0;++fn;close(sv);}' $localword;
)&
fi
done
wait #wait
for name in $format; do mv "$name" "${name//___/ }"; done
echo All files done.
Since i couldnt figure out how to enter awk files with spaces , im using
for name in $format; do mv "$name" "${name//___/ }"; done
I think this would be a lot easier to handle with awk:
awk -F" " 'BEGIN{filenumber=1}{counter+=NF}{print $0 > FILENAME"_part_"filenumber} counter>1000{counter=0;++filenumber}' yourinputfile
awk here is:
Splitting each line by space -F" "
Before processing the file set the filenumber variable to 1
Bump the counter variable by the number of fields in the line {counter+=NF}
Print out the line to the file, numbered by a variable. Using the FILENAME built-in variable here to pull through yourinputfile. {print $0 > FILENAME"_part_"filenumber}
If the counter has popped over 1000, then send it back to 0 and bump the filenumber variable by 1 counter>1000{counter=0;++filenumber}
Minimized a bit:
awk -F" " 'BEGIN{fn=1}{c+=NF}{print $0>FILENAME"_part_"fn}c>1000{c=0;++fn}' yourinputfile

Why $1 output is nothing?

I wrote a simple bash script and in the end of that I tried to test positional arguments like $0, $1, ...
echo please enter your name
read name
if [ -z "$name" ]
then
echo please enter your name
fi
if [ -n "$name" ]
then
echo Thank you so much
fi
echo $0
echo $1
echo $2
echo $3
After I run that, the output was:
please enter your name
j
Thank you so much
/bin/reza.sh
Why just $0 had output and other had nothing?
Run it like below
./bin/reza.sh first second third
please enter your name
monk
Thank you so much
/bin/reza.sh
first
second
third
Also, $0 is file name of the script itself.
The arguments you enter to a script are take in the order $1,$2,$3 and so on.
In this testscript:
#!/bin/bash
echo $0 #Gives you the command/script name itself
echo $1 #Gives you the first argument
echo $2 #Gives you the second argument
echo $3 #Gives you the third argument
echo $# #Gives you all arguments
echo $# #Gives you the total number of arguments excluding the script name
So the result of
$./testscript a b c
is
./testscript
a
b
c
a b c
3
If the argument is not assigned, its value is null or nothing will be printed.
$ printf "%sThere is nothing before this.\n" $1
gives you :
There is nothing before this.
Note: Don't use echo to test arguments, echo will append a newline at the end automatically as in bash.

String together awk commands

I'm writing a script that searches a file, gets info that it then stores into variables, and executes a program that I made using those variables as data. I actually have all of that working, but I need to take it a step further:
What I currently have is
#!/bin/sh
START=0
END=9
LOOP=10
PASS=0
for i in $(seq 0 $LOOP)
do
LEN=$(awk '/Len =/ { print $3; exit;}' ../../Tests/shabittestvectors/SHA1ShortMsg.rsp)
MSG=$(awk '/Msg =/ { print $3; exit; }' ../../Tests/shabittestvectors/SHA1ShortMsg.rsp)
MD=$(awk '/MD =/ { print $3; exit; }' ../../Tests/shabittestvectors/SHA1ShortMsg.rsp)
echo $LEN
echo $MSG
MD=${MD:0:-1}
CIPHER=$(./cyassl hash -sha -i $MSG -l $LEN)
echo $MD
echo $CIPHER
if [ $MD == $CIPHER ]; then
echo "PASSED"
PASS=$[PASS + 1]
echo $PASS
fi
done
if [ $PASS == $[LOOP+1] ]; then
echo "All Tests Successful"
fi
And the input file looks like this:
Len = 0
Msg = 00
MD = da39a3ee5e6b4b0d3255bfef95601890afd80709
Len = 1
Msg = 00
MD = bb6b3e18f0115b57925241676f5b1ae88747b08a
Len = 2
Msg = 40
MD = ec6b39952e1a3ec3ab3507185cf756181c84bbe2
All the program does right now, is read the first instances of the variables and loop around there. I'm hoping to use START and END to determine the lines in which it checks the file, and then increment them every time it loops to obtain the other instances of the variable names, but all of my attempts have been unsuccessful so far. Any ideas?
EDIT: Output should look something like, providing my program "./cyassl" works as it should
0
00
da39a3ee5e6b4b0d3255bfef95601890afd80709
da39a3ee5e6b4b0d3255bfef95601890afd80709
PASSED
1
00
bb6b3e18f0115b57925241676f5b1ae88747b08a
bb6b3e18f0115b57925241676f5b1ae88747b08a
PASSED
2
40
ec6b39952e1a3ec3ab3507185cf756181c84bbe2
ec6b39952e1a3ec3ab3507185cf756181c84bbe2
PASSED
etc.
There's no need to make multiple passes on the input file.
#!/bin/sh
exec < ../../Tests/shabittestvectors/SHA1ShortMsg.rsp
status=pass
awk '{print $3,$6,$9}' RS= | {
while read len msg md; do
if test "$(./cyassl hash -sha -i $msg -l $len)" = "$md"; then
echo passed
else
status=fail
fi
done
test "$status" = pass && echo all tests passed
}
The awk will read from stdin (which the exec redirects from the file; personally I would skip that line and have the caller direct input appropriately) and splits the input into records of one paragraph each. A "paragraph" here means that the records are separated by blank lines (the lines must be truly blank, and cannot contain whitespace). Awk then parses each record and prints the 3rd, 6th, and 9th field on a single line. This is a bit fragile, but for the shown input those fields represent length, message, and md hash, respectively. All the awk is doing is rearranging the input so that it is one record per line. Once the data is in a more readable format, a subshell reads the data one line at a time, parsing it into the variables named "len", "msg", and "md". The do loop processes once per line of input, spewing the rather verbose message "passed" with each test it runs (I would remove that, but retained it here for consistency with the original script), and setting the status if any tests fail. The braces are necessary to ensure that the value of the variable status is retained after the do loop terminates.
The following code,
inputfile="../../Tests/shabittestvectors/SHA1ShortMsg.rsp"
while read -r len msg md
do
echo got: LEN:$len MSG:$msg MD:$md
#cypher=$(./cyassl hash -sha -i $msg -l $len)
#continue as you wish
done < <(perl -00 -F'[\s=]+|\n' -lE 'say qq{$F[1] $F[3] $F[5]}' < "$inputfile")
for your input data, produces:
got: LEN:0 MSG:00 MD:da39a3ee5e6b4b0d3255bfef95601890afd80709
got: LEN:1 MSG:00 MD:bb6b3e18f0115b57925241676f5b1ae88747b08a
got: LEN:2 MSG:40 MD:ec6b39952e1a3ec3ab3507185cf756181c84bbe2
If your input data is in order you can have this with a simplified bash:
#!/bin/bash
LOOP=10
PASS=0
FILE='../../Tests/shabittestvectors/SHA1ShortMsg.rsp'
for (( I = 1; I <= LOOP; ++I )); do
read -r LEN && read -r MSG && read -r MD || break
echo "$LEN"
echo "$MSG"
MD=${MD:0:-1}
CIPHER=$(exec ./cyassl hash -sha -i "$MSG" -l "$LEN")
echo "$MD"
echo "$CIPHER"
if [[ $MD == "$CIPHER" ]]; then
echo "PASSED"
(( ++PASS ))
fi
done < <(exec awk '/Len =/,/Msg =/,/MD =/ { print $3 }' "$FILE")
[[ PASS -eq LOOP ]] && echo "All Tests Successful."
Just make sure you don't run it as sh e.g. sh script.sh. bash script.sh most likely.

command line argument in shell scripting

HI all i am newbie to scripting, i am here with problem ,that i am not able to pass command line variable to my script .
biz$: ./myproject.sh -x file2
My(given) myproject has these contents:
Type ="" //here i pass first argument
while [ $# -gt 0]
case "$1" in
-x) shift; type = "x" >&2;shift ;;
-y) shift; type = "y" >&2;shift ;;
###################################################
BEGIN{
if ($7 == '/'){
if ($2 != "zzzz"){
printf ("error",$0);
if ($3 < 111){
printf ("error", $0);
}
file = " " //here i want to pass my argument file2.
Please help me out to solve this, i am not able to move furthur without solving this, i am new guy to scripting. I cant cange $2 $3 $7..Experts pls i need your suggestion.
I believe that you are using BASH and you want to obtain the command line parameters into two variable inside your script. In which case, the professional approach is to use 'getopts'
Please refer to this link : bash command line arguments for further details.
#!/bin/sh
# First line above, if this is a bourne shell script
# If this is a bash script use #!/bin/bash
# Assume this script is called from the command line with the following:
# ./myproject.sh -x file2 -y one two 110 four five six /
#Type ="" \\ here i pass first argument
# Comments are preceeded with # followed by a space
# No spaces around = for assignment of values
# Empty string "" not necessary
Type= # Here i pass first argument
#while [ $# -gt 0] # Spaces required just inside []
while [ $# -gt 0 ]
do
case "$1" in
# -x) shift; type = "x" >&2;shift ;;
# >&2 Redirects standard out to standard error (stdout, stderr)
# and usually is not needed unless explicitly generating error
# messages
# Type is not the same as type; however, you are trying to
# load the file variable
-x) shift; file=$1; shift ;;
-y) shift; Type=y # Get rid of -y only
;;
one) if [ "$7" = '/' ] # Space around = for tests
then
echo error $0 >&2
fi
if [ "$2" != zzzz ]
then
echo $2 is not equal to zzzz
fi
if [ "$3" -lt 111 ] # -lt is less than
then
echo "$3 is less than 111"
fi
break # break out of while loop
;;
esac
echo Cmd Ln Args left: "$#"
done
echo file: $file, Type: $Type, \$3: $3, \$7: $7
####################################################
# The code below is awk code. Its functionality was
# placed under case one above
# BEGIN{
# if ($7 == '/'){
# if ($2 != "zzzz"){
# printf ("error",$0);
#
# if ($3 < 111){
# printf ("error", $0);
# }
#
# file = " " //here i want to pass my argument file2.
OUTPUT:
Cmd Ln Args left: -y one two 110 four five six /
Cmd Ln Args left: one two 110 four five six /
error ./myproject.sh
two is not equal to zzzz
110 is less than 111
file: file2, Type: y, $3: 110, $7: /

Resources