Have unique values in each while loop iteration - bash

What I try to achieve, is to define global variables in my script. These variables can be reused in a loop (preferably a while loop..) and with every iteration, the loop should get a new set a variables.
My script (so far):
PACKAGE_ASSET_ID=AUTO`date +%s`000001
TITLE_ASSET_ID=AUTO`date +%s`000002
MOVIE_ASSET_ID=AUTO`date +%s`000003
PREVIEW_ASSET_ID=AUTO`date +%s`000004
POSTER_ASSET_ID=AUTO`date +%s`000005
while read name; do
#DATE=`date +%s`
#PACKAGE_ASSET_ID="AUTO${DATE}000001"
#TITLE_ASSET_ID="AUTO${DATE}000002"
#MOVIE_ASSET_ID="AUTO${DATE}000003"
#PREVIEW_ASSET_ID="AUTO${DATE}000004"
#POSTER_ASSET_ID="AUTO${DATE}000005"
echo $PACKAGE_ASSET_ID
echo $TITLE_ASSET_ID
echo $MOVIE_ASSET_ID
echo $PREVIEW_ASSET_ID
echo $POSTER_ASSET_ID
done <names.txt
Within the file names.txt, there are 15 entries. For every entry, the while loop needs to process these sets of variables. Giving me something like
AUTO1521884581000001
AUTO1521884581000002
AUTO1521884581000003
AUTO1521884581000004
AUTO1521884581000005
AUTO1521884592000001
AUTO1521884592000002
AUTO1521884592000003
AUTO1521884592000004
AUTO1521884592000005
As you can see in the script, I tried putting it into the while loop and with different syntax but regretfully, without success. The results I get are always the same set of variables, for all the 15 entries.

Did you really expect that bash (even bash!) would need more than a second to read one line?? Try adding the nanoseconds.
while read name; do
DATE=$(date +%s%N)
PACKAGE_ASSET_ID="AUTO${DATE}000001"
TITLE_ASSET_ID="AUTO${DATE}000002"
MOVIE_ASSET_ID="AUTO${DATE}000003"
PREVIEW_ASSET_ID="AUTO${DATE}000004"
POSTER_ASSET_ID="AUTO${DATE}000005"
echo $PACKAGE_ASSET_ID
echo $TITLE_ASSET_ID
echo $MOVIE_ASSET_ID
echo $PREVIEW_ASSET_ID
echo $POSTER_ASSET_ID
done <names.txt

Related

Update global variable from while loop

Having trouble updating my global variable in this shell script.
I have read that the variables inside the loops run on a sub shell. Can someone clarify how this works and what steps I should take.
USER_NonRecursiveSum=0.0
while [ $lineCount -le $(($USER_Num)) ]
do
thisTime="$STimeDuration.$NTimeDuration"
USER_NonRecursiveSum=`echo "$USER_NonRecursiveSum + $thisTime" | bc`
done
That particular style of loop does not run in a sub-shell, it will update the variable just fine. You can see that in the following code, equivalent to yours other than adding things that you haven't included in the question:
USER_NonRecursiveSum=0
((USER_Num = 4)) # Add this to set loop limit.
((lineCount = 1)) # Add this to set loop control variable initial value.
while [ $lineCount -le $(($USER_Num)) ]
do
thisTime="1.2" # Modify this to provide specific thing to add.
USER_NonRecursiveSum=`echo "$USER_NonRecursiveSum + $thisTime" | bc`
(( lineCount += 1)) # Add this to limit loop.
done
echo ${USER_NonRecursiveSum} # Add this so we can see the final value.
That loop runs four times and adds 1.2 each time to the value starting at zero, and you can see it ends up as 4.8 after the loop is done.
While the echo command does run in a sub-shell, that's not an issue as the backticks explicitly capture the output from it and "deliver" it to the current shell.

Change name of Variable while in a loop

I have this idea in mind:
I have this number: CN=20
and a list=( "xa1-" "xa2-" "xb1-" "xb2-")
and this is my script:
for a in "${list[#]}"; do
let "CN=$(($CN+1))"
echo $CN
Output:
21
22
23
24
I am trying to create a loop where it creates the following variables, which will be referenced later in my script:
fxp0_$CN="fxp-$a$CN"
fxp0_21="fxp-xa1-21"
fxp0_22="fxp-xa2-22"
fxp0_23="fxp-xb1-23"
fxp0_24="fxp-xb2-24"
However, I have not been able to find a way to change the variable name within my loop. Instead, I was trying myself and I got this error when trying to change the variable name:
scripts/srx_file_check.sh: line 317: fxp0_21=fxp0-xa2-21: command not found
After playing around I found the solution!
for a in "${list[#]}"; do
let "CN=$(($CN+1))"
fxp_int="fxp0-$a$CN"
eval "fxp0_$CN=${fxp_int}"
done
echo $fxp0_21
echo $fxp0_22
echo $fxp0_23
echo $fxp0_24
echo $fxp0_25
echo $fxp0_26
echo $fxp0_27
echo $fxp0_28
Output:
fxp0-xa1-21
fxp0-xa2-22
fxp0-xb1-23
fxp0-xb2-24
fxp0-xc1-25
fxp0-xc2-26
fxp0-xd1-27
fxp0-xd2-28
One common method for maintaining a dynamically generated set of variables is via arrays.
When the variable names vary in spelling an associative array comes in handy whereby the variable 'name' acts as the array index.
In this case since the only thing changing in the variable names is a number we can use a normal (numerically indexed) array, eg:
CN=20
list=("xa1-" "xa2-" "xb1-" "xb2-")
declare -a fxp0=()
for a in "${list[#]}"
do
(( CN++ ))
fxp0[${CN}]="fxp-${a}${CN}"
done
This generates:
$ declare -p fxp0
declare -a fxp0=([21]="fxp-xa1-21" [22]="fxp-xa2-22" [23]="fxp-xb1-23" [24]="fxp-xb2-24")
$ for i in "${!fxp0[#]}"; do echo "fxp0[$i] = ${fxp0[$i]}"; done
fxp0[21] = fxp-xa1-21
fxp0[22] = fxp-xa2-22
fxp0[23] = fxp-xb1-23
fxp0[24] = fxp-xb2-24
As a general rule can I tell you that it's not a good idea to modify names of variables within loops.
There is, however, a way to do something like that, using the source command, as explained in this URL with some examples. It comes down to the fact that you treat a file as a piece of source code.
Good luck

Iterating over variable name in bash script

I needed to run a script over a bunch of files, which paths were assigned to train1, train2, ... , train20, and I thought 'why not make it automatic with a bash script?'.
So I did something like:
train1=path/to/first/file
train2=path/to/second/file
...
train20=path/to/third/file
for i in {1..20}
do
python something.py train$i
done
which didn't work because train$i echoes train1's name, but not its value.
So I tried unsuccessfully things like $(train$i) or ${train$i} or ${!train$i}.
Does anyone know how to catch the correct value of these variables?
Use an array.
Bash does have variable indirection, so you can say
for varname in train{1..20}
do
python something.py "${!varname}"
done
The ! introduces the indirection, so "get the value of the variable named by the value of varname"
But use an array. You can make the definition very readable:
trains=(
path/to/first/file
path/to/second/file
...
path/to/third/file
)
Note that this array's first index is at position zero, so:
for ((i=0; i<${#trains[#]}; i++)); do
echo "train $i is ${trains[$i]}"
done
or
for idx in "${!trains[#]}"; do
echo "train $idx is ${trains[$idx]}"
done
You can use array:
train[1]=path/to/first/file
train[2]=path/to/second/file
...
train[20]=path/to/third/file
for i in {1..20}
do
python something.py ${train[$i]}
done
Or eval, but it awfull way:
train1=path/to/first/file
train2=path/to/second/file
...
train20=path/to/third/file
for i in {1..20}
do
eval "python something.py $train$i"
done

Executing script variable by variable

i have a script & it goes as below,
instant_client="/root/ora_client/instantclient_11_2"
output=`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select count (1) from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF
exit
`
query=(`$instant_client/sqlplus -s HRUSER/HRUSER#TOMLWF <<EOF
set heading off
set feedback off
set lines 10000
set pagesize 10000
select o.candidateid from onboardingcandidates o, candidatedetails c where o.candidateid=c.candidateid and o.JOININGSTATUS='0091' and to_date(o.joiningdate)=to_date(sysdate+5);
EOF`)
i=0
echo "Throwing individual arrays:"
while [ $i -lt $output ]
do
a=${query[$i]}
echo Candidate[$i]=$a
i=$(($i+1))
done
OUTPUT:
Throwing individual arrays:
Candidate[0]=cand1
Candidate[1]=cand2
Candidate[2]=cand3
Candidate[3]=cand62
REQUIRED OUTPUT
Everything is working fine.
All i need is, i need 1 output at a time.
i.e. if i run the above script then the output should be controlled.
It should throw 1 output at a time on the prompt.
Is this possible ??
IF YOU NEED ANYTHING MORE THEN PLZ ASK. I HOPE I AM CLEAR WITH MY DOUBT
So you're running two queries, one to get the count of the number of results, the second to get the results.
If you want to only have one query, you can iterate through the count of the number of results. as the variable query is an array, you can use:
${#query[*]}
as the number of result rows, then use:
while [ $i -lt ${#query[*]} ]
as the loop condition.
If you want to display one result at a time, and require an enter between them, then you can add a read after the echo.
If you want to display a specific return row, then, assuming that the routine is called as-is, then the row number to display is passed in as the first parameter $1, then you can use:
a=${query[$1]}
echo Candidate[$1]=$a
if you just want to display the result at that line, without the Candidate[] text, then you can just echo:
echo ${query[$1]}
If I have understood your question correctly, before your echo statement to print the output,put this line:
read dummy
This will prompt you to enter some key, when entered, will show the next line output.

Simple timer to measure seconds an operation took to complete

I run my own script to dump databases into files on a nightly basis.
I wanted to count time (in seconds) it takes to dump each database, so I was trying to write some functions to help me achieve it, but I'm running into problems.
I am no expert in scripting in bash, so if I'm doing it plain wrong, just say so and ideally suggest alternative, please.
Here's the script:
#!/bin/bash
declare -i time_start
function get_timestamp {
declare -i time_curr=`date -j -f "%a %b %d %T %Z %Y" "\`date\`" "+%s"`
echo "get_timestamp:" $time_curr
return $time_curr
}
function timer_start {
get_timestamp
time_start=$?
echo "timer_start:" $time_start
}
function timer_stop {
get_timestamp
declare -i time_curr=$?
echo "timer_stop:" $time_curr
declare -i time_diff=$time_curr-$time_start
return $time_diff
}
timer_start
sleep 3
timer_stop
echo $?
The code should really be quite self-explanatory. echo commands are only for debugging.
I expect the output to be something like this:
$ bash timer.sh
get_timestamp: 1285945972
timer_start: 1285945972
get_timestamp: 1285945975
timer_stop: 1285945975
3
Now this is not the case unfortunately. What I get is:
$ bash timer.sh
get_timestamp: 1285945972
timer_start: 116
get_timestamp: 1285945975
timer_stop: 119
3
As you can see, the value that local var time_curr gets from the command is a valid timestamp, but returning this value causes it to be changed to an integer between 0 and 255.
Can someone please explain to me why this is happening?
PS. This obviously is just my timer test script without any other logic.
UPDATE
Just to be perfectly clear, I want this to be part of a bash script very similar to this one, where I want to measure each loop cycle.
Unless of course I can do it with time, then please suggest a solution.
You don't need to do all this. Just run time <yourscript> in the shell.
$? is used to hold the exit status of a command and can only hold a value between 0 and 255. If you pass an exit code outside this range (say, in a C program calling exit(-1)), the shell will still receive a value in that range and set $? accordingly.
As a workaround, you could just set a different value in your bash function:
function get_timestamp {
declare -i time_curr=`date -j -f "%a %b %d %T %Z %Y" "\`date\`" "+%s"`
echo "get_timestamp:" $time_curr
get_timestamp_return_value=$time_curr
}
function timer_start {
get_timestamp
#time_start=$?
time_start=$get_timestamp_return_value
echo "timer_start:" $time_start
}
...
I believe you should be able to use the existing "time" function.
After Update to the question:
This was the bit of script from your link which was doing a for loop.
# dump each database in turn
for db in $databases; do
echo $db
$MYSQLDUMP --force --opt --user=$USER --password=$PASSWORD
--databases $db > "$OUTPUTDIR/$db.bak"
done
You could extract the inner portion of the loop into a new script (call it dump_one_db.sh)
and do this inside the loop:
# dump each database in turn
for db in $databases; do
time dump_one_db.sh $db
done
Make sure to write the output of the time against the db name into some file.
This is happening because return codes need to be between 0-255. You can't return an arbitrary number. If you continue to refuse to use the builtin time function and roll your own, change your functions to echo their stamp and use a process expansion ($()) to grab the value.

Resources