2

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?

1
  • So for k=4 you would have 1_0_0_0 0_1_0_0 0_0_1_0 0_0_0_1? Commented Jun 25, 2017 at 4:57

5 Answers 5

2

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
Sign up to request clarification or add additional context in comments.

Comments

1

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"

2 Comments

i am not sure the character subtitiution works... other way it could be done ?
@mastersplinter: What version of bash do you run?
1

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

Comments

0

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

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.