I am trying to allocate a bunch of temp files in a loop and export them from within the loop. I then want to loop thru again and echo the values.
for (( i=1; i<=5; i++ ))
do
dd if=/dev/zero of=/tmp/mh1_$i.out bs=1024 count=1024 status=none
declare TEMP_FILE_${i}="/tmp/mh1_${i}.out"
export "TEMP_FILE_${i}"
done
If I do a echo $TEMP_FILE_1 it correctly prints /tmp/mh1_1.out
But when I try this in a loop it prints 1, 2, 3, 4 and 5.
for (( i=1; i<=5; i++ ))
do
echo $TEMP_FILE_${i} --> This prints the i value instead of /tmp/mh1_x.out
done
How do I escape the index $i in the echo above to see the real file name ?
I suggest using the mktemp utility with arrays:
# create tmp files
tmp_files=()
for ((i=0;i<5;++i)); do
tmp_files+=("$(mktemp --tmpdir mh1_XXXXXX.out)") || exit 1
done
# process all tmp files
for file in "${tmp_files[#]}"; do
echo "$file"
# do something with the file ...
done
# list all tmp files
printf '%s\n' "${tmp_files[#]}"
# list 2nd tmp file
echo "${tmp_files[1]}"
In order to make your code work, you need to use variable indirection and change your second for loop to:
for ((i=1;i<=5;++i)); do
var=temp_file_$i
echo "${!var}"
done
Don't use uppercase variables as they could clash with environmental or internal shell variables. Also, note that export is needed only when you want to pass the variables to child processes in the environment.
Why not use bash arrays?
export temp_file
loop
temp_file[$i]="/tmp/mh1_${i}.out"
...
endloop
Then loop over the array
Related
I have N files in my directory, I want to be able to loop through them with batches, for example for 2/3/4 files I want to execute one command. I saw something like this, but can't find it, unfortunately. I will try to explain what I want using pseudo code, for example:
i=0
while i<N:
a=getFile(i)
b=getFile(i+1)
dosomething a
dosomething b
i+=2
Is there any way to do it in Bash? Right now I'm using regexp, but it gets one file at a time (I'm using *.ext because all files have one extension, so you can just loop through all files in the directory in your answer, if it's easier):
for j in *.ext; do
...
done
This would be the same with most programming languages: loop and store items somewhere until you have enough of them:
declare -i count=0
declare -a files=()
for f in *.ext; do
files[count]="$f"
(( count += 1 ))
if (( count == 2 )); then
dosomething "${files[0]}"
dosomething "${files[1]}"
count=0
fi
done
If you want to process your files in batches of more than 2 at a time we can also design something a bit more generic (adapt the value of batch):
declare -i batch=3
declare -i count=0
declare -a files=()
for f in *.ext; do
files[count]="$f"
(( count += 1 ))
if (( count == batch )); then
for (( i=0; i<batch; i++ )); do
dosomething "${files[i]}"
done
count=0
fi
done
You can collect your arguments into an array, and then slice that any way you like.
array=( *.ext )
for ((i=0; i<=${#array[#]}; i+=2)); do
dosomething "${array[i]}" "${array[i+1]}"
done
I'm making a simple script that iterates through the files in the current directories,
the $1 is for a size parameter and the others $1,$2 ..... are for the manipulated files and set for the file names.
the problem is after using the for loop the variable are losing their value and start with integers like 1,2,3, and the script doesn't work unless I use files named as 1,2,3,....
How can I keep the original values?
ex:
./script 50 my_first_file .....
#!/bin/bash
size=$1
allfiles=$#
shift
#here the value of the $1 is "my_first_file"
for ((i = 1 ; i < allfiles ; i++))
do
#here the value of the $1 = 1
done
Instead of using a for loop with integers, you can loop on arguments directly like this:
#!/bin/bash
size="$1"
allfiles=$#
shift
counter=1
for i in "$#"
do
echo "$counter= $i"
(( counter = counter + 1 ))
done
echo "size= $size"
This will show you each argument in sequence.
If you need to show or use the position of each argument, you can use a counter.
If I call this: script.bash 25 a b c
The output is:
1= a
2= b
3= c
size= 25
Another option is just use a short hand of looping through the files.
#!/usr/bin/env bash
size=$1
shift
counter=1
for f; do
printf '%d. %s\n' "$((counter++))" "$f"
done
printf 'size=%s\n' "$size"
Why doesn't my for loop: for ((i=1 ;i<=$n, i++)) work? I can not figure this out. when n is for example 4, the line echo $n returns 4 but it does not go into the loop again. I don't get any errors either. I tried to make a small loop like:
for ((i=1, i<=$n; i++)); do
echo "this works"
done
This works fine which makes it even stranger to me :/. Thanks in advance
read n
length=16
p=()
p[1]=50
rest=63
function s() {
arr=($#)
line="_____________________________________________________________________"
for i in ${arr[#]}; do
line=$( echo $line | sed s/./1/$i)
done
echo $line
}
for ((i=1; i<=$n; i++)); do
echo $n
for ((j=1; j<=$length; j++)); do
s ${p[#]}
done
len=${#p[#]}
((len=$len*2))
for ((k=1; k<=$len; k+=2)); do
((p[$k+1]=p[$k]+1))
((p[$k]=p[$k]-1))
done
for ((l=1; l<=$length; l++)); do
s ${p[#]}
len=${#p[#]}
for ((m=1; m<=$len; m+=2)); do
((p[$m+1]=p[$m+1]+1))
((p[$m]=p[$m]-1))
done
done
((rest=$rest-2*$length))
((length=$length/2))
done
If you don't declare your variables local, they're global -- so the loop in your s function is overwriting the same i counter used outside the function, leading to the outer loop's early exit.
Consider using the below code:
s() {
local -a arr # declare a function-local array (sparse, like all bash arrays)
local i # ...and a function-local counter
for i; do # by default, a for statement iterates over "$#"; that works for us.
arr[$i]=1 # specifically set a value only for named items
done
# ...thereafter, iterate through the range of characters we want to print...
for ((i=0; i<70; i++)); do
printf '%s' "${arr[$i]:-_}" # and print the array entry if present, or an _ otherwise
done
printf '\n' # ...followed by a trailing newline.
}
I am writing a script to add data to a file after the script has been run.
Since I need to mail the data forward, I need a variable to assign the number of times the script has been called.
I am using a temp file which stores the value of count. Every time the script is called the variable temp is called, the value incremented and stored in count. The incremented value is than stored back to the temp.
count=$((temp + 1))
echo $count > temp
printf "%d\t%10s\t" "$count" "$datet" >> table
this is the code i'm using, but temp is not increasing...?
Just read the previous value before anything else:
temp=$(cat temp)
count=$((temp + 1))
echo "$count" > temp
printf "%d\t%10s\t" "$count" "$datet" >> table
Test
$ echo "0" > temp
$ ./a
$ cat temp
1
$ ./a
$ cat temp
2
You have to use cat temp to get the value inside the file temp.
But I would suggest to use a variable for the temporary file for better code readeablility:
TMP=/tmp/counter
if [ ! -f $TMP ]; then echo "0">$TMP; fi
count=$(($(cat $TMP) + 1))
echo $count > $TMP
printf "%d\t%10s\t" "$count" >> /tmp/somelogfile
Or in one line, if you don't need the count in a variable:
echo "$(($(cat $TMP) + 1))">$TMP
Then you can later use:
echo $(cat $TMP)
I have several .jpg images in a folder that have names like:
20140331_134927.jpg
20140331_124933.jpg
20140331_124933.jpg
etc..
I want to rename them to something like:
Agra-1.jpg
Agra-2.jpg
Agra-3.jpg
etc..
I tried running the following script (stored as my.sh):
for files in *.jpg; do
i=1
echo mv "$files" "Agra-$i.jpg"
i=$((i+1))
done
However, if I were to run that without the echo, all files would be renamed to "Agra-1.jpg"
Why does this not work as I expect and how should this be written?
Put the assignment out of the loop:
i=1 # only once
for files in *.jpg; do
mv "$files" "Agra-$i.jpg"
let i++
done
Here is an example - you should declare the counter variable outside of the loop otherwise it will be reset to its initial value on each iteration:
Inside loop:
$ for file in *; do i=1; echo $i; (( i++ )); done
1
1
1
Outside loop:
$ i=1
$ for file in *; do echo $i; (( i++ )); done
1
2
3