Create files inside folders with nested loops and arrays - arrays

I am trying to create 2 folders and some files inside them. But it can't create more than the 1st folder and the 1st file. Code says it can't create the 1st folder since it is exist. Don't even try to create the rest of the files and folders.
Here is what I tried
#!/bin/bash
declare -a arrRel=(rel20 rel21)
declare -a arrVar=(pt_el pt_mu)
declare -a arrVarTitle=("electron p_T" "muon p_T")
for i in "${arrRel[#]}"
do
mkdir "${arrRel[$i]}"
cd "${arrRel[$i]}"
for j in "${arrVar[$j]}"
do
textFile=text_${arrRel[$i]}_${arrVar[$j]}.txt
targetDir=Desktop/samples
cat >${textFile} <<EOF
"some tex"
EOF
done #arrVar
cd ../ #cd arrRel
done #for loop over releases
To sum up, there should be 2 folders, rel20 and rel21 and two text files in both. But I just get the folder rel20 and just one text file in it.
I'd appreciate if you can point me why this doesn't work.

I think from what you posted, that his is what you are looking for.
#!/bin/bash
declare -a arrRel=(rel20 rel21)
declare -a arrVar=(pt_el pt_mu)
declare -a arrVarTitle=("electron p_T" "muon p_T")
for i in "${arrRel[#]}"
do
mkdir "$i"
cd "$i"
for j in "${arrVar[#]}"
do
textFile=text_$i_$j.txt
targetDir=Desktop/samples
cat >${textFile} <<EOF
"some tex"
EOF
done #arrVar
cd ../ #cd arrRel
done
Not sure what your intent for arrVarTitle is.

You're indexing the arrays incorrectly. Frankly, the arrays are adding no value, and they're not worth the confusion. Just do:
#!/bin/bash
for i in rel20 rel21; do
( # This open paren is important
mkdir -p $i
cd $i
for j in pt_el pt_mu; do
textFile=text_$i_$j.txt
targetDir=Desktop/samples
cat >${textFile} <<-EOF
"some tex"
EOF
done
) # end subshell to recover previous working directory
done

Related

bash: make an array for the files in the same directory

I am working with the ensemble of the mol2 filles located in the same directory.
structure36S.mol2 structure30S.mol2 structure21.mol2
structure36R.mol2 structure30R.mol2 Structure20R.mol2
structure35S.mol2 structure29R.mol2 Structure19R.mol2
structure35R.mol2 structure28R.mol2 Structure13R.mol2
structure34S.mol2 structure27R.mol2
structure34R.mol2 structure26.mol2 jacks18.mol2
structure33S.mol2 structure25.mol2 5p9.mol2
structure33R.mol2 structure24.mol2 Y6J.mol2
structure32R.mol2 structure23.mol2 06I.mol2
structure31R.mol2 structure22.mol2
From this data I need to make an associative array with the names of the filles (without extension (mol2)) as well as some value (7LMF) shared between all elements:
dataset=( [structure36S]=7LMF [structure36R]=7LMF [structure35S]=7LMF ...[06I]=7LMF [Y6J]=7LMF )
We may start from the following script:
for file in ./*.mol2; do
file_name=$(basename "$file" .mol2)
#some command to add the file into the array
done
How this script could be completed for the creating of the array?
I would recommend turning on nullglob otherwise the pattern will evaluate as a string when there is no match.
Use parameter expansion to remove the file extension.
If the leading './' is included, it will need to be stripped with another expansion.
#!/usr/bin/env bash
shopt -s nullglob
declare -A dataset
for file in *.mol2; do
dataset+=([${file%.*}]=7LMF)
done
for key in "${!dataset[#]}"; do echo "dataset[$key]: ${dataset[$key]}"; done
Try this Shellcheck-clean code:
#! /bin/bash -p
shopt -s nullglob
declare -A dataset
for file in *.mol2; do
file_name=${file%.mol2}
dataset[$file_name]=7LMF
done
# Show the contents of 'dataset'
declare -p dataset

transform file content into array or grep for values

I have a file containing config information and a shell script that reads that file. I want to hand over values to a bash script.
file.txt
varNumber=1.1.1
varName=testThis
varFile=~/myDir/mySubDir/output.zip
myShellScript.sh
FILENAME="~/myDir/mySubDir/output.zip" <- this is what I expect from grep/awk
startNextScript.sh -f $FILENAME
I would like to extract the variables either as an associated array or - if easier - grep for them,
but as I'm not used to writing commands like this in bash I am asking for help!
Using associative array in bash:
#!/bin/bash
declare -A vars
while read -r line ; do
var=${line%%=*} # Remove everything after the first =.
value=${line#*=} # Remove everything before the first =.
vars[$var]=$value
done < file.txt
echo Number: ${vars[varNumber]}
echo Name: ${vars[varName]}
echo File: ${vars[varFile]}

Store all subdirectories of /Volumes in an array (BASH)

I need a script that will get all of the directories within the /Volumes directory on a Mac and store them in an array. The problem that I am running into is that it is very common for there to be a space in a directory name, and that really messes things up.
Here is what I've got so far:
LOCATION="/Volumes"
COUNTER=0
cd $LOCATION
OIFS=$IFS
IFS=$'\n'
for folder in *; do
[ -d "$folder" ] || continue
(( DRIVES[$COUNTER] = ${folder} ))
(( COUNTER = COUNTER + 1 ))
done
IFS=$OIFS
Here is the error that I am getting:
./getDrives.sh: line 17: DRIVES[0] = Macintosh HD : syntax error in expression (error token is "HD ")
I guess the simplest is just:
array=( /Volumes/*/ )
Notes:
use this with nullglob or failglob set
if you also want hidden directories (but not . nor ..), set dotglob
if you want all the directories and subdirectories (recursively), set globstar and use
array=( /Volumes/**/ )
instead.
When I say set nullglob or failglob or dotglob or globstar I mean the shell options, that can be set with, e.g.:
shopt -s nullglob
and unset with, e.g.:
shopt -u nullglob
More about these in The Shopt Builtin section of the Bash Reference Manual.
To answer your comment: you only want the basename of the directories, not the full path? easy, just do
cd /Volumes
array=( */ )
That's all. In fact, I'm suggesting you replace 6 lines of inefficient code with just one, much more efficient, line.
More generally, if you don't want to cd into /Volumes, you can easily get rid of the leading /Volumes/ like so
array=( /Volumes/*/ )
array=( "${array[#]/#\/Volumes\//}" )
Or, even better, put the leading /Volumes/ in a variable and proceed as:
location="/Volumes/"
array=( "$location"* )
array=( "${array[#]/#"$location"/}" )
cd /Volumes
cnt=0
for d in *; do
[ -d "$d" ] || continue
drv[$cnt]="$d"
((++cnt))
done
for d in "${drv[#]}"; do
echo "$d"
done

Bash script with using special characters in variable array and copy to folder

I've a new question about a closed question from me.
In the last one I asked for help in fixing a script, which sorts files to folders by it's content. (Bash script which sorts files to folders by it's content; How to solve wildcard in variables?)
Now I have a new problem with that.
The variables had changed. The old ones where single word variables in an array, now I've multiple words with special characters as variable.
Here is my script:
#!/bin/bash
declare -a standorte;
standorte=('Zweigst: 00' 'Zweigst: 03' 'Zweigst: 08')
ls lp.3.* | while read f
do
for ort in "${standorte[#]}"; do
grep -i $ort "$f" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo Copying $f to $ort
cp "$f" $ort
fi
done
done
Now you see, the "ort" is the folder name. So the script try to copy the file lp.3.* to e.g. Zweigst: 00. But without the escape backslashes it doesn't work. Put I escape charakters into the variable, the script doesn't work, because in the file lp.3.* is no "Zweigst:\ 00".
I think, I must declare a new variable for "ort" where I put the folder names in it.
But I've no idea how to change the for loop. I must say the script, when you found Zweigst: 00 copy this file to folder "zweigst00". I'm sorry my bash script experience is not good at all. I can't change this by my own.
I have multiple (zero to unlimited) lp.3.* files (e.g. lp.3.1, lp.3.2, lp.3.5.2 and so on)
In this files is this text: http://pastebin.com/0ZzCUrpx
You just need to quote the variable:
for ort in "${standorte[#]}"; do
grep -i "$ort" "$f" >/dev/null 2>&1
# ^----^-------- quotes needed
if [ $? -eq 0 ]; then
echo Copying $f to $ort
cp "$f" "$ort"
# ^----^-------- quotes needed
fi
done
Why? Because otherwise this
grep -i $ort "$f" >/dev/null 2>&1
gets expanded as something that grep cannot understand properly:
grep -i Zweigst: 00 "$f" >/dev/null 2>&1
see that it is trying to grep Zgeigst: from file 00.

Bash script - how to fill array?

Let's say I have this directory structure:
DIRECTORY:
.........a
.........b
.........c
.........d
What I want to do is: I want to store elements of a directory in an array
something like : array = ls /home/user/DIRECTORY
so that array[0] contains name of first file (that is 'a')
array[1] == 'b' etc.
Thanks for help
You can't simply do array = ls /home/user/DIRECTORY, because - even with proper syntax - it wouldn't give you an array, but a string that you would have to parse, and Parsing ls is punishable by law. You can, however, use built-in Bash constructs to achieve what you want :
#!/usr/bin/env bash
readonly YOUR_DIR="/home/daniel"
if [[ ! -d $YOUR_DIR ]]; then
echo >&2 "$YOUR_DIR does not exist or is not a directory"
exit 1
fi
OLD_PWD=$PWD
cd "$YOUR_DIR"
i=0
for file in *
do
if [[ -f $file ]]; then
array[$i]=$file
i=$(($i+1))
fi
done
cd "$OLD_PWD"
exit 0
This small script saves the names of all the regular files (which means no directories, links, sockets, and such) that can be found in $YOUR_DIR to the array called array.
Hope this helps.
Option 1, a manual loop:
dirtolist=/home/user/DIRECTORY
shopt -s nullglob # In case there aren't any files
contentsarray=()
for filepath in "$dirtolist"/*; do
contentsarray+=("$(basename "$filepath")")
done
shopt -u nullglob # Optional, restore default behavior for unmatched file globs
Option 2, using bash array trickery:
dirtolist=/home/user/DIRECTORY
shopt -s nullglob
contentspaths=("$dirtolist"/*) # This makes an array of paths to the files
contentsarray=("${contentpaths[#]##*/}") # This strips off the path portions, leaving just the filenames
shopt -u nullglob # Optional, restore default behavior for unmatched file globs
array=($(ls /home/user/DIRECTORY))
Then
echo ${array[0]}
will equal to the first file in that directory.

Resources