Create a loop for 3 different variables to output all possible combinations - bash

So lets say i have 3 lines of code
ABC
123
!##
How do i create a for loop to output the number of ways to piece them together?
E.G ABC123!##, ABC!##123, 123ABC!##$
here is my current line of code
#!/bin/bash
alphabet='ABC' numbers='123' special='!##'
for name in $alphabet$numbers$special
do
echo $name
done
echo done

alphabet='ABC' numbers='123' special='!##'
for name1 in $alphabet $numbers $special
#on 1st iteration, name1's value will be ABC, 2nd 123 ...
do
for name2 in $alphabet $numbers $special
do
for name3 in $alphabet $numbers $special
do
#here we ensure that we want strings only as combination of that three strings
if [ $name1 != $name2 -a $name2 != $name3 ]
then
echo $name1$name2$name3
fi
done
done
done
if you want also to print strings, like 123123123 and ABCABCABC, remove if condition

You can also do it without a loop at all using brace expansion (but you lose the ability to exclude, e.g. ABCABCABC). For example:
#!/bin/bash
alpha='ABC'
num='123'
spec='!##'
printf "%s\n" {$alpha,$num,$spec}{$alpha,$num,$spec}{$alpha,$num,$spec}
Example Use/Output
$ bash permute_brace_exp.sh
ABCABCABC
ABCABC123
ABCABC!##
ABC123ABC
ABC123123
ABC123!##
ABC!##ABC
ABC!##123
ABC!##!##
123ABCABC
123ABC123
123ABC!##
123123ABC
123123123
123123!##
123!##ABC
123!##123
123!##!##
!##ABCABC
!##ABC123
!##ABC!##
!##123ABC
!##123123
!##123!##
!##!##ABC
!##!##123
!##!##!##

Related

Generate a column for each file matching a glob

I'm having difficulties with something that sounds relatively simple. I have a few data files with single values in them as shown below:
data1.txt:
100
data2.txt
200
data3.txt
300
I have another file called header.txt and its a template file that contains the header as shown below:
Data_1 Data2 Data3
- - -
I'm trying to add the data from the data*.txt files to the last line of Master.txt
The desired output would be something like this:
Data_1 Data2 Data3
- - -
100 200 300
I'm actively working this so I'm not sure where to begin. This doesn't need to be implemented in pure shell -- use of standard UNIX tools such as awk or sed is entirely reasonable.
paste is the key tool:
#!/bin/bash
exec >>Master.txt
cat header.txt
paste $'-d\n' data1.txt data2.txt data3.txt |
while read line1
do
read line2
read line3
printf '%-10s %-10s %-10s\n' "$line1" "$line2" "$line3"
done
As a native-bash implementation:
#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Bash 4.0+ needed" >&2; exit 1;; esac
declare -A keys=( ) # define an associative array (a string->string map)
for f in data*.txt; do # iterate over data*.txt files
name=${f%.txt} # for each, remove the ".txt" extension to get our name...
keys[${name^}]=$(<"$f") # capitalize the first letter, and read the file to get the value
done
{ # start a group so we can redirect output just once
printf '%s\t' "${!keys[#]}"; echo # first line: keys in our associative array
printf '%s\t' "${keys[#]//*/-}"; echo # second line: convert values to dashes
printf '%s\t' "${keys[#]}"; echo # third line: print the values unmodified
} >>Master.txt # all the above with output redirected to Master.txt
Most of the magic here is performed by parameter expansions:
${f%.txt} trims the .txt extension from the end of $f
${name^} capitalizes the first letter of $name
"${keys[#]}" expands to all values in the array named keys
"${keys[#]//*/-} replaces * (everything) in each key with the fixed string -.
"${!keys[#]}" expands to the names of entries in the associative array keys.

Shell Script : How to add in the end of lines which contains special string

I have a VAR which contain :
list_data="toto
titi
tata
tete"
My array can contain like this example or more values then 3 data :
arraytest[0]="Hello|Test|env|tata|POLO|GER|GO|"
arraytest[1]="GOODNIGHT|Test2|env2|tete|GOLF|ITA|NOTGO|"
arraytest[2]="AFTER|Test3|env3|JAJA|CIT|FRA|GO|"
and my string is
string="INSERT"
What I want to do is to add special string in the end of each line where every line contain each value of list_data
For example :
arraytest[0]="Hello|Test|env|tata|POLO|GER|GO|INSERT"
arraytest[1]="GOODNIGHT|Test2|env2|tete|GOLF|ITA|NOTGO|INSERT"
arraytest[2]="AFTER|Test3|env3|JAJA|CIT|FRA|GO|"
I try this
echo ${arraytest[*]} | sed -i 's/$/ $string'
Please Help.
Thank you.
bash solution:
string="INSERT"
pat="(${list_data//$'\n'/|})"
for i in "${!arraytest[#]}"; do
[[ "${arraytest[$i]}" =~ $pat ]] && arraytest[$i]+=$string
done
The final arraytest contents:
echo ${arraytest[*]}
Hello|Test|env|tata|POLO|GER|GO|INSERT GOODNIGHT|Test2|env2|tete|GOLF|ITA|NOTGO|INSERT AFTER|Test3|env3|JAJA|CIT|FRA|GO|
Details:
pat="(${list_data//$'\n'/|})" - constructing regex pattern(pat contains (toto|titi|tata|tete))
${!arraytest[#]} - the basic signature format is ${!name[*]} - if name is an array variable, expands to the list of array indices (keys) assigned in name.
Loop over the individual elements of the array (rather than ${array[*]} )
for ((i=0 ; i<${#arraytest[*]} ; i++))
do
echo ${arraytest[${i}]} | sed "s/$/|${string}/"
done

get query string in array with bash

I have a sqlite with a table with 2 columns. I would like to get the two values of the columns in every variable or in an array. For instance:
table A
COLUMN A COLUMN B
credit and risk David
nothing susan
.....
and I would like to obtain: Variable A="credit and risk" and variable B="David" then Variable A ="nothing" and variable B= "susan" and so on.
I'm trying with these code but if the column A have space I can't get the string complete, for example I obtain "credit" only. My code:
valores=($(sqlite3 alcampo.db "select DESCRIPTION, URL FROM SUBCATEGORYS"))
cnt=${#valores[#]}
echo "cuenta es ... $cnt"
for (( i=0 ; i<cnt ; i++ ))
do
echo "Record No. $i: ${valores[$i]}"
fieldA=${valores[0]}
echo "campo a es ... $fieldA"
fieldB=${valores[1]}
echo "campo B es ... $fieldB"
done
Could you help me please? Thanks
There might be better ways to get this done.
It sounds like you don't want to keep the variables after you echo them.
while read line; do
fieldA=$( echo "$line" | sed -n "s/\(.*\)\s\{2,\}.*/\1/p" )
fieldB=$( echo "$line" | sed -n "s/.*\s\{2,\}\(.*\)/\1/p" )
echo "campo A es ... ${fieldA}"
echo "campo B es ... ${fieldB}"
done < <(sqlite3 alcampo.db "select DESCRIPTION, URL FROM SUBCATEGORYS")
This will ready your command "sqlite3 ..." directly into the while loop. The while loop will assign each line to the variable "$line".
We then echo the $line variable and sed it to grab the information we want. The sed is based on having 2 or more spaces between the columns...it was the only way I could think to delimit the data based off of what you posted.
$( ) -- command substitution
-n -- don't print
s -- substitute
\( -- begin capture group 1
.* -- match anything
\) -- end capture group 1
\s{2,} -- 2 or more white-space characters
.* -- anything else
\1 -- output capture group 1
p -- print it
I hope this helps. Let me know.

Variable assignment when reading from file using cat

I have a txt file that is in the format below:
name1 path/to/some/directory
name2 path/to/some/other/directory
name3 path/to/some/directory
name4 path/to/some/other/directory
...
Here is the code I have written to read this file line by line:
NUM=1
for line in $(cat /path/to/my/file.txt); do
if [ $((NUM%2)) -eq 1 ]
then
name= $line #this line does not work
echo $line #while this line works just fine
else
sudo tar -cf /desired/path/$name.tar $line
fi
NUM=$((NUM+1))
done
This code actually reads file word by word, and it alternates between then and else of if statement. Once it assigns a value it has read to variable name (then part inside if), then it uses that variable in command that is performed in else part of if. (This is how I expect it to work.)
The problem that arises is that variable assignment in then part of if seems not to work, it sees word it has just read as command, and doesn't assign its value to variable. I tried to echo it and it works just fine.
Why name= $line variable assignment is not working?
Thank you for any suggestions, comments or answers.
The assignments in bash require no space around =.
Hence, you need to say:
name="$line"
^ ^
quotes!
This happens because anything happening after the declaration is considered a command. See for example this, that tries to define r to 2 and then echo 1 is executed:
$ r=2 echo 1
1
This is why it is also a good thing to quote the declaration: name="$line".
Regarding the parsing and definition of variables of the file, you can maybe use this approach:
declare $('s/\s\+/="/; s/$/"/' a)
This replaces the spaces in between the first and second word by =" and the end of line with ". This way, name /path/ gets converted into name="/path/". By using declare, this command gets executed and makes variables be ready for use.
$ cat a
name1 aa
name2 rr
name5 hello
$ sed 's/\s\+/="/; s/$/"/' a
name1="aa"
name2="rr"
name5="hello"
$ declare $('s/\s\+/="/; s/$/"/' a)
So now you have the variables ready to use:
$ echo "$name5"
hello
And finally, note that this is equivalent (and better) than for line in $(cat /path/to/my/file.txt):
while IFS= read -r val1 val2 ...
do
... things ...
done < /path/to/my/file.txt

How would I let the user set a variable to be used in a line of code?

So I have wanted to know if it was possible for a user to set a variable to be used in a code like:
Word 1="Example 1"
Word 2="example 2"
echo $Word 1 $Word 2
Then it would say
Example 1 example 2
I know that this works
But I want to know if its possible to make it so the user of the script could be asked to input the value of word 1 and word 2 like this
what should word one be: 123
What should word two be : 456
Then it would plant the data in the code and the script would generate and run this command:
echo $Word 1 $Word 2
And it would say
123 456
You're looking for the read built-in command.
Example:
% cat reading.bash
#!/bin/bash
echo -n "what should word one be: "
read one
echo -n "what should word two be: "
read two
echo "${one} ${two}"
Running:
% ./reading.bash
what should word one be: abc
what should word two be: xyz
abc xyz

Resources