Bash: iterate through files based on regex parameter - bash

There are several posts about iterating through bash files like this:
count_files() {
count=0
for f in "filename_*.txt"
do
count=$(($count + 1))
done
echo "Current count:$count"
}
I need to pass in "filename_*.txt" as a param when calling the bash script. Like this:
$: count_files.sh "filename_*.txt"
$: count_files.sh "different_filename_*.txt"
This, however, only gets the first file:
count_files() {
count=0
for f in $1
do
count=$(($count + 1))
done
echo "Current count:$count"
}
How do I pass in a regex param and iterate through it?
NOTE: counting the files is just an example. If you have a simple way to do that, please share, but that's not the main question.

Inside count_files.sh script make sure you call function with quotes like this:
count_files "$1"
instead of:
count_files $1
Later will get you count=1 because wildcard will be expanded before function call to the first file name.

Related

Bash scripting: variable is not incrementing correctly

I am writing a bash script to loop through all the directories and rename the directory to the value of the array, but it seems my (i th) value is not incrementing correctly and it also says "(i th) command not found" when I run my bash script.
Here is my code: I replaced the values inside Unix with place holder values.
#!/bin/bash
declare -a Unix=(value1 value2 value3 .... );
i = 0
for d in */; do
echo ${Unix[$i]}
#mv $d ${Unix[$i]}
(($i+1))
done
You are doing two things wrong. Firstly , to answer your problem,
(($i+1))
should be
(($i+=1))
also, you should remove the spaces in the line
i = 0
so it looks like
i=0
Firstly, you might want to quote your directory names in the mv command, or you get into trouble with names containing spaces:
mv "$d" "${Unix[i]}"
As you see, it's not necessary to prepend the i in the index with $, as [] is an "arithmetic context" here and expands variable names.
Secondly, your increment does nothing: you just add 1 to i and throw the result away. You can use the increment operator instead:
(( ++i ))
Again, the $ is not needed.

shell: build variable with multiple paths and commands

Is there a way to build a varible like this:
var="-i \"/path to/file 1.mp4\" -i \"/path to/file 2.mp4\""
And then use this later in a program:
ffmpeg $var
I know \" doesn't work, and eval works in a way, but eval can be ugly.
Is there a solution without eval?
The next best thing to do is to build an array. When you put ${var[#]} somewhere, it will replace it with the complete array contents. If you put "${var[#]}" somewhere (with quotes), the elements of the array will be quoted, so elements with spaces will not be split at the whitespace into multiple elements:
#!/bin/bash
function test() {
for ((i=0; i<$#; i++)) {
echo "Param $i: ${!i}"
}
}
var[0]="-i"
var[1]="/a/path"
var[2]="-i"
var[3]="/second/path with space/"
test "${var[#]}"
Will output:
Param 0: test.sh
Param 1: -i
Param 2: /a/path
Param 3: -i
and that is exactly what you require.
I only tried this in bash, other shells may behave differently.

read multiple values from a property file using bash shell script

Would like to read multiple values from a property file using a shell script
My properties files looks something like below, the reason I added it following way was to make sure, if in future more students joins I just need to add in in the properties file without changing any thing in the shell script.
student.properties
total_student=6
student_name_1="aaaa"
student_name_2="bbbb"
student_name_3="cccc"
student_name_4="dddd"
student_name_5="eeee"
When I run below script I not getting the desired output, for reading the student names from properties file
student.sh
#!/bin/bash
. /student.properties
i=1
while [ $i -lt $total_student ]
do
{
std_Name=$student_name_$i
echo $std_Name
#****** my logic *******
} || {
echo "ERROR..."
}
i=`expr $i + 1`
done
Output is something like this
1
2
3
4
5
I understand the script is not getting anything for $student_name_ hence only $i value is getting printed.
Hence, wanted to know how to read values from the properties file.
You can do variable name interpolation with ${!foo}. If $foo is "bar", then ${!foo} gives you the value of $bar. In your code that means changing
std_Name=$student_name_$i
to
var=student_name_$i
std_Name=${!var}
Alternatively, you could store the names in an array. Then you wouldn't have to do any parsing.
student.properties
student_names=("aaaa" "bbbb" "cccc" "dddd" "eeee")
student.sh
#!/bin/bash
. /student.properties
for student_name in "${student_names[#]}"; do
...
done
You can use indirect expansion:
std_Name=student_name_$i
echo "${!std_Name}"
the expression ${!var} basically evaluates the variable twice:
first evaluation: student_name_1
second evaluation: foo
Note that this is rarely a good idea and that using an array is almost always preferred.

Assigning dynamic value to variable

how can I assign a dynamic value to variable? The simplest method I know about is by using a function. For example
fn(){
VAR=$VAL
}
VAL=value
fn
echo $VAR
will output
value
but I want something simpler, like
VAR=$VAL
VAL=value
echo $VAR
to output
value
What command should I use? Preferably to be compatible with dash.
Thanks!
UPDATE: Removed #!/bin/sh in connection to dash. Thank "Ignacio Vazquez-Abrams" for the explanation!
UPDATE 2: Adding the source for my script to better understand the situation.
INPUT=`dpkg -l|grep ^rc|cut -d' ' -f3`
filter(){
echo *$A*
}
for A in $INPUT;do find ~ -iname `filter`|grep ^$HOME/\\.|grep -iz --color $A;done
This script should help finding the remaining configuration files of removed packages.
Okay, if function is not good, then maybe calling eval is okay?
export VAR='echo $VAL'
VAL=10
eval $VAR
This will display
10
How about a simple function that sets value?
# export is needed so f() can use it.
export VAR
f() {
VAR=$#
}
f 10
echo $VAR
f 20
echo $VAR
The code above will display:
10
20
If I understand your needs, you want an indirection, so try the following shell code (tested with dash) :
var=foo
x=var
eval $x=another_value
echo $var
output :
another_value
finally:
Each times you need to modify var, you need to run eval $x=foobar

cat: can't open '/tmp/drive/P0.RAW': No such file or directory

The script pasted below causes the following error:
cat: can't open '/tmp/drive/P0.RAW': No such file or directory
It looks like the script does not properly evaluate $N for the filename.
How $N be made to evaluate so the file name is something like P01L.RAW, P02L.RAW, etc.?
N=1
until [ $N -ge 10 ]; do
cat bmpheader.bmp /tmp/drive/P0$NL.RAW > ./P0$NL.bmp
./quality_metric_test ./P0$NL.bmp
N=$((N + 1))
done
Your problem is that bash interprets all uppercase characters as part of the variable by default, so it's looking for $NL instead of just $N. This is why it returns just P0.RAW, as $NL is an unexisting variable. You can easily avoid that by a minor syntax adjustment, call the variable with curly brackets ({ and }) around it. Replace this:
cat bmpheader.bmp /tmp/drive/P0$NL.RAW > ./P0$NL.bmp
./quality_metric_test ./P0$NL.bmp
With this:
cat bmpheader.bmp /tmp/drive/P0${N}L.RAW > ./P0${N}L.bmp
./quality_metric_test ./P0${N}L.bmp
That should do the trick.

Resources