I have a shell script that gets the number of CPUs, loops from 0 up to that number, prints the counter, creates a temporary file for each CPU, and increments the counter. The script is:
#!/usr/local/bin/bash
StartUp_Run=false
Iterator_For_File_Toucher_With_NCPU_While=0
Total_NCPU_For_File_Toucher_With_NCPU_while=$(nproc --all)
while true
do
if [ "$StartUp_Run" = false ]; then
while [ "$Iterator_For_File_Toucher_With_NCPU_While" -lt "$Total_NCPU_For_File_Toucher_With_NCPU_while" ]; do
echo "$Iterator_For_File_Toucher_With_NCPU_While"
touch "core${Iterator_For_File_Toucher_With_NCPU_While}-temp_orders.csv"
let "Iterator_For_File_Toucher_With_NCPU_While+=1"
done
echo "ncpu amount = $Total_NCPU_For_File_Toucher_With_NCPU_while"
StartUp_Run=true
fi
done
When I run it using `sh LastStage.sh`, I see values such as 0, 1, 1, 2, 2, and so on. Why is every value except the first being printed twice?
4 Answers
If the output still looks wrong, enable tracing immediately after the shebang with `set -x` and run the script with Bash. The trace will show every command actually executed and can reveal an unsaved extra `echo`, an alias or function named `let`, or the fact that a different shell is interpreting the file.
There are a few portability and correctness issues worth fixing too. Use `=` rather than `==` in the single-bracket test, quote variables, and avoid the endless `while true` loop unless it has a real purpose or a delay. Also, `touch` updates the timestamp of an existing file; if you only want to ensure that a file exists, redirecting output to it may be more appropriate depending on your goal.
The main issue is that you're explicitly running the file with `sh`, so the Bash shebang is ignored. `sh` may point to a different shell, such as `dash`, and its handling of `let` can differ. Make the script executable and run it directly instead:
`chmod +x LastStage.sh`
`./LastStage.sh`
Alternatively, invoke Bash explicitly with `bash LastStage.sh`. Also check that the file you're running is saved and doesn't contain an extra `echo` after the increment. In Bash, the loop as shown prints each counter only once.
The loop can be simplified considerably. There is no need for an infinite outer loop because the inner loop already performs the one-time initialization. Use Bash arithmetic instead of `let`, and quote expansions:
`cpu=0`
`ncpu=$(nproc --all)`
`while (( cpu < ncpu )); do`
` echo "$cpu"`
` touch "core${cpu}-temp_orders.csv"`
` ((cpu++))`
`done`
`echo "ncpu amount = $ncpu"`
This should produce one line for each value from 0 through `ncpu - 1`.
`let i++` and `((i++))` are equivalent in Bash, but arithmetic syntax makes it clearer that the command is intended for numeric operations. The important part here is using Bash consistently rather than running the script through an arbitrary `sh` implementation.

That was the issue—thanks!