Reputation: 3515
I've written a short script which needs to find some text using regex.
I'm incrementing a counter inside a while loop, and this counter is part of another command. Unfortunately this command is always running with the initial counter.
Here a snippet from my code:
COUNTER=1
LAST_COMMIT=`git log remotes/origin/devel --pretty=oneline --pretty=format:%s | head -${COUNTER}`
JIRA_ID=`echo $LAST_COMMIT | grep -o -P '[A-Z]{2,}-\d+' | xargs`
while [[ ! -z "$JIRA_ID" && $COUNTER -lt "5" ]]; do
echo "This is the current counter: $COUNTER"
echo "This is the last commit $LAST_COMMIT"
COUNTER=$[COUNTER+1]
done
echo "this is the counter outside the loop $COUNTER"
Upvotes: 0
Views: 83
Reputation: 295403
The best-practices way to encapsulate code (as per BashFAQ #50) is with a function:
get_last_commit() {
git log remotes/origin/devel --pretty=oneline --pretty=format:%s \
| sed -n "$(( $1 + 1)) p"
}
Then:
while (( counter < 5 )); do
last_commit=$(get_last_commit "$counter")
IFS=$'\n' read -r -d '' -a jira_id \
< <(grep -o -P '[A-Z]{2,}-\d+' <<<"$last_commit") ||:
[[ $jira_id ]] || break
echo "This is the current counter: $counter"
echo "This is the last commit $last_commit"
echo "Found ${#jira_id[@]} jira IDs"
printf ' %s\n' "${jira_id[@]}"
(( counter++ ))
done
Other notes:
read -a
, here, reads the JIRA IDs into an array; you can then ask for the array's length (with ${#jira_id[@]}
), expand a specific entry from the array (with ${jira_id[0]}
to get the first ID, [1]
for the second, etc); expand them all into an argument list (with "${jira_id[@]}"
), etc.$(( ... ))
is the POSIX-standard way to enter a math context; (( ))
, without a leading $
, is a bash extension.[[ ]]
and (( ))
does not require double quotes to prevent glob expansion or string-splitting, double quotes should be used around expansions in (almost) all other cases.sed '2 p'
gets line 2 more efficiently than head -2 | tail -n 1
.However, even that is much less efficient than just calling git log
only one single time and iterating over its results.
while IFS= read -r -u 3 last_commit; do
IFS=$'\n' read -r -d '' -a jira_id \
< <(grep -o -P '[A-Z]{2,}-\d+' <<<"$last_commit") ||:
[[ $jira_id ]] || continue
echo "Found ${#jira_id[@]} jira IDs"
printf ' %s\n' "${jira_id[@]}"
done 3< <(git log remotes/origin/devel --pretty=oneline --pretty=format:%s)
Upvotes: 2
Reputation: 123470
Bash is a procedural language, meaning it contains a series of steps to be carried out in order.
LAST_COMMIT=`...`
is a step that sets the variable LAST_COMMIT
to the value of the command. You have made this step only execute once, which is why you see the same value over and over.
If you want it to execute again for new values of $COUNTER
, you can place the statement inside the loop:
while
LAST_COMMIT=`git log remotes/origin/devel --pretty=oneline --pretty=format:%s | head -${COUNTER} | tail -n 1`
JIRA_ID=`echo $LAST_COMMIT | grep -o -P '[A-Z]{2,}-\d+' | xargs`
[[ ! -z "$JIRA_ID" && $COUNTER -lt "5" ]]
do
echo "This is the current counter: $COUNTER"
echo "This is the last commit $LAST_COMMIT"
COUNTER=$[COUNTER+1]
done
echo "this is the counter outside the loop $COUNTER"
Since the steps in the loop are executed multiple times, the LAST_COMMIT=`...`
step is also executed multiple times, each time with a new value for $COUNTER
.
Upvotes: 0