master splinter
master splinter

Reputation: 21

Create file names within a for loop

I need a way in which I can within a for loop generate a lot a directory using mkdir.

for i in $(seq 1 1 ${k})
do
   mkdir ...
done

The name of folder is a name with k numbers, such as 0_0_1 in which case k = 3.

The for-loop has to generate different names in which the position of 1 changes. so the names generated and directory created should be

1_0_0, 0_1_0, 0_0_1 for k = 3

and in that order as well.

is this possible?

Upvotes: 2

Views: 971

Answers (5)

dawg
dawg

Reputation: 103744

To create your first pattern for any value of n you can create a binary number with bc and then insert the _ between each digit with awk:

$ n=5
$ fn=$(echo "obase=2;2^($n-1)" | bc | awk '$1=$1' FS= OFS="_" )
$ echo "$fn"
1_0_0_0_0

Then you can rotate that pattern with awk in a Bash loop. Here with a larger n to demonstrate:

n=7
fn=$(echo "obase=2;2^($n-1)" | bc | awk '$1=$1' FS= OFS="_" )
for (( i=1 ; i<=$n ; i++ )); do
    (( i > 1 )) && fn=$(echo "$fn" | awk '{t=$(n-1); $(n-1)=$n; $n=t; print }' n="$i" FS="_" OFS="_")
    echo "$fn"   # here mkdir "$fn"
done    
1_0_0_0_0_0_0
0_1_0_0_0_0_0
0_0_1_0_0_0_0
0_0_0_1_0_0_0
0_0_0_0_1_0_0
0_0_0_0_0_1_0
0_0_0_0_0_0_1

Upvotes: 0

mklement0
mklement0

Reputation: 437111

A pure Bash solution (no calls to external utilities): Tip of the hat to archimiro for encouraging me to initialize the array in a Bash loop too.

# Determine the number of digits
k=3

# Create an array with the specified number of digits
# initialized to 0s (e.g., with k = 3, `( 0 0 0 )`).
arr=()
for (( i = 0; i < k; ++i )); do arr[i]='0'; done

# Loop over all digits and set each one to 1 in isolation.
IFS='_' # set IFS, the internal field separator, also used when printing arrays as strings
for (( i = 0; i < k; ++i )); do
    arr[i]=1
    # Inside "...", with index [*], the array elements are joined with 
    # the 1st char. in $IFS.
    echo "${arr[*]}"
    arr[i]=0
done

Note: For brevity I've omitted saving and restoring the original $IFS value above, something that is advisable in real-world scripts.

The above yields:

1_0_0
0_1_0
0_0_1

Upvotes: 2

MauricioRobayo
MauricioRobayo

Reputation: 2356

This might be the ugliest way to do it, or at least not the fastest one. But anyhow here it goes:

k=3

template=$(printf "%0*d" "$k" | sed 's/./&_/g')

for ((i=1; i<=k*2; i+=2)); do

    echo $(sed "s/./1/$i" <<<${template%_})

done

And of course we can try to remove the sed inside the loop to speed things a bit:

k=3

template=$(printf "%0*d" "$k" | sed 's/./&_/g')

for ((i=0; i<k*2; i+=2)); do

    j=i+1

    file=${template:0:$i}1${template:$j}

    echo ${file%_}

done

Upvotes: 0

ericthewry
ericthewry

Reputation: 21

Here is a double for-loop that will print the appropriate names to stdout

k=4
for i in $(seq 1 1 ${k})
do 
    name="0"
    if [[ "$i" -eq "1" ]]; then
        name="1"
    fi

    for j in $(seq 2 1 ${k})
    do
        if [[ "$i" -eq "$j" ]]; then
            name="${name}_1"
        else
            name="${name}_0"
        fi
    done
    echo "$name" #to make directories replace with mkdir "$name"
done

Running this script with k set to 4 gives the output

$ ./filemaker.sh
1_0_0_0
0_1_0_0
0_0_1_0
0_0_0_1

Upvotes: 1

choroba
choroba

Reputation: 241768

You can use a loop to create the first file name, then use substitution in a loop to create the other names:

#!/bin/bash
k=4
s=''
for ((i=1; i<k; i++)) ; do
    s+=0_
done
s+=1

while [[ $s != 1* ]] ; do
    echo "$s"
    s=${s/0_1/1_0}
done
echo "$s"

Upvotes: 1

Related Questions