Variable as bash array index? - linux

#!/bin/bash
set -x
array_counter=0
array_value=1
array=(0 0 0)
for number in ${array[#]}
do
array[$array_counter]="$array_value"
array_counter=$(($array_counter + 1))
done
When running above script I get the following debug output:
+ array_counter=0
+ array_value=1
+ array=(0 0 0)
+ for number in '${array[#]}'
+ array[$array_counter]=1
+ array_counter=1
+ for number in '${array[#]}'
+ array[$array_counter]=1
+ array_counter=2
+ for number in '${array[#]}'
+ array[$array_counter]=1
+ array_counter=3
Why does the variable $array_counter not expand when used as index in array[]?

Bash seems perfectly happy with variables as array indexes:
$ array=(a b c)
$ arrayindex=2
$ echo ${array[$arrayindex]}
c
$ array[$arrayindex]=MONKEY
$ echo ${array[$arrayindex]}
MONKEY

Your example actually works.
echo ${array[#]}
confirms this.
You might try more efficient way of incrementing your index:
((array_counter++))

Related

Shell script, stop running if failed

I have a shell script that runs a test repeatedly :
#!/bin/tcsh
set x = 1
while ($x <= 10000)
echo $x
./test
# x += 1
end
I am trying to adapt it to break the loop and stop running if the test failed, i.e. the test executable returned with a non-zero status. I thought the following change would work.
#!/bin/tcsh
set x = 1
set y = 0
while ($x <= 10000 && $y == 0)
echo $x
# y = ./test
# x += 1
end
But, I get error #: Expression syntax
Can you please tell me what did I do wrong, and how to capture the return value of ./test in a variable so I can break the loop, or some other way to break the loop upon encountering the test failure
I'm not a fan of scripting in csh, and I highly advise against it. However, in this case, csh seems to do the right thing, and you can simply do:
#!/bin/tcsh
set x = 1
while ($x <= 10000)
echo $x
./test || break
# x += 1
end

Split string in ksh

I got a string as follow :
foo=0j0h0min0s
What would be the best way to convert it in seconds without using date ?
I tried something like this that sounded pretty nice but no luck :
#> IFS=: read -r j h min s <<<"$foo"
#> time_s=$((((j * 24 + h) * 60 + min) * 60 + s))
ksh: syntax error: `<' unexpected
Any idea is welcome, I just can't use date -d to make conversion as it is not present on the system I am working on.
<<<"$foo" is mainly a bash-ism. It is supported in some/newer ksh. (google 'ksh here string' ).
Your read is trying to split at :, wich is not present in your input
If you first get rid of characters, you can split at blank (as ususal)
and changing the here-string to a here-doc
#!/bin/ksh
foo=1j2h3min4s
read -r j h min s << END
"${foo//[a-z]/ }"
END
# or echo "${foo//[a-z]/ }" | read -r j h min s
time_s=$((((j * 24 + h) * 60 + min) * 60 + s))
echo ">$foo< = >${foo//[a-z]/ }< = $j|$h|$min|$s => >$time_s<"
>1j2h3min4s< = >1 2 3 4 < = "1|2|3|4 " => >93784<
# or using array, easy to assign, more typing where used
typeset -a t=( ${foo//[a-z]/ } )
time_s=$(( (( t[0] * 24 + t[1]) * 60 + t[2]) * 60 + t[3] ))
echo ">$foo< = >${foo//[a-z]/ }< = ${t[0]}|${t[1]}|${t[2]}|${t[3]} => >$time_s<"

pbsnodes and bash string matching

I have a string of the form: "8, 14-24, 30-45, 9", which is a substring of the output of pbsnodes. This shows the cores in use on a given node, where 14-24 is a range of cores in use.
I'd like to know the total number of cores in use from this string, i.e.
1 + (24 - 14 + 1) + (45 - 30 + 1 )+ 1 in this example, using a bash script.
Any suggestions or help is much appreciated.
Michael
You could use pure bash techniques to achieve this. By reading the string to array and doing the arithmetic operator using the $((..)) operator. You can run these commands directly on the command-line,
IFS=", " read -ra numArray <<<"8, 14-24, 30-45, 9"
unset count
for word in "${numArray[#]}"; do
(( ${#word} == 1 )) && ((++count)) || count=$(( count + ${word#*-} - ${word%-*} + 1 ))
done
printf "%s\n" "$count"
The idea is
The read with -a splits the string on the de-limiter set by IFS and reads it into the array numArray
A loop on each of the elements, for each element, if the element is just single character, just increment total count by 1
For numeric ranges, do manipulation as e.g. for number a-b use parameter expansion syntax ${word#*-} and ${word%-*} to extract b and a respectively and do b-a+1 and add it with count calculated already and print the element after the loop
You can put this in a bash script with she-bang set to #!/bin/bash and run the script or run it directly from the command-line

Shell for loop, stopping at declaration

I'm trying to write a for loop that goes from 1 to 10, then calculates ( 1 through 10 mod 5) + 2. After that I want to display it like this (1 to 10 mod 5) + 2 = answer. However i'm getting an error at the beginning of the loop which is a syntax error.
for (( i = 0; i <= 10; i++)); do
calculate=(i % 5) + 2
echo ("("i "% 5) + 2" calculate)
done
Try these changes:
calculate=$(( i % 5 + 2 ))
# $(( ... )) is the shell's way to do arithmetic
echo "($i % 5) + 2 = " $calculate
# $x is a way to refer to the value of variable x
# (also inside a double-quoted string)
The for loop header is actually OK.

remove specific character from a string with batch script

i want to remove only a specific character into a string and only one time. for example, if I have this file:
"1234 + test.txt"
i want to remove "+" character. my problem is that I don't know how many "+" could be in filename; by the way, I want to remove only the first:
"1234 ++ test + hello + world.txt"
need to be:
"1234 + test + hello + world.txt"
I need to do this with a bat script. I have some problems to use correctly "token,delims" parameters....
edit: I've a problem with Edoro's solution. if filename is "++plus--.txt", %left% is "plus--.txt" and %right% is +plus--.txt
pure batch
#echo off &setlocal
set "string=1234 ++ test + hello + world.txt"
for /f "delims=+" %%i in ("%string%") do set "left=%%i"
set "right=%string:*+=%"
set "new=%left%%right%"
echo %new%
..output is:
1234 + test + hello + world.txt
Go through a sed script:
echo "1234 + test + hello + world.txt" | sed 's/+//'

Resources