Checking if array element is empty with for loop in bash - linux

Can you please provide a sample code for checking if array element is empty using for loop?
None of this worked for me:
declare -a f=( 'file' )
for ((i=0; ${f[$i]}; i++); do echo "i: $i"; done
for ((i=0; `test -n "${f[$i]}"`; i++); do echo "i: $i"; done
What I wanted is to keep this braces-like for style and iterate over array, following solution worked for me:
for((i=0; i < ${#f[#]}; i++))
Does any other syntax available?

This might work
for i in ${f[#]}
do
if [ -z "$f[$i]" ]
then
#do whatever you want
fi
done

Related

How do you search an array for a variable using bash's test [ ] built-in?

Using the test built-in to compare my variable to an array fails with error "Syntax error in expression".
I've tried requoting the var_names, using == and -eq, and several old tricks from SO questions from 8+ years ago.
#!/bin/bash
TOTAL=0
declare -a FREQ=(0);
main(){
for i in $(cat "$1");
do
TOTAL=$(( $i + FREQ[-1] ))
echo Total is $TOTAL
if [[ $TOTAL -eq "${FREQ[#]}" ]];
then
echo "Matching Frequency Found: " $TOTAL
exit
else
FREQ=(${FREQ[#]} $TOTAL)
fi
done
return $TOTAL
return $FREQ
}
main $#
I expect $TOTAL to be found in the array of $FREQ when the script is called with ./script.sh input.txt which holds over 1000 integers.
I'm not sure I get what you're trying to do, but try a lookup table.
TOTAL=0
declare -a FREQ=(0)
declare -A lookup=( [0]=1 )
while read -r i
do TOTAL=$(( $i + FREQ[-1] ))
if (( ${lookup[$TOTAL]} ))
then echo "Matching Frequency Found: " $TOTAL
exit
else lookup[$TOTAL]=1
FREQ+=($TOTAL)
fi
done < "$1"
As that logic stands, though, I don't think it will ever hit a found frequency unless some of them are negative...

erreur commande cut script shell

while i want to execute this script, the execution was blocked at the cut command and the man cut was displayed
the script code
#!/bin/bash
for i in `cat newcontext` ;do
var1=`cut –f1 –d" " $i`
var2=`cut –f2 –d" " $i`
if [ $var2 = false ];then
for j in `cat adaptrules`;do
c=`cut -f1 -d" " $j`
cc=`cut -f2 -d" " $j`
if [ $c = $var1 ];then
r=$cc
fi
done
sed /$var1/d currentconfig>>newconfig
else
for k in `cat adaptrules`;do
var3=`cut –f1 –d" " $k`
var4=`cut –f2 –d" " $k`
if [ $var3 = $var1 ];then
action=$var4
fi
done
cat $action >> newconfig
fi
done
It's difficult to know if you are trying to read from a file named in the variables i, j, and k, or if you are trying to just parse the lines of newcontext and adaptrules. In either case you should simply not use cut at all. If you are attempting the latter, you can instead do something like:
#!/bin/bash
while read var1 var2 ; do
if test "$var2" = false; then
while read c cc ; do
if test "$c" = "$var1"; then
r=$cc
fi
done < adaptrules
<&- sed /$var1/d currentconfig>>newconfig #WTF: multiple iterations with only one line omitted?
else
while read var3 var4 ; do
if test "$var3" = "$var1"; then
action=$var4
fi
done < adaptrules
<&- cat $action >> newconfig # Does $action really name a file?
# I'm guessing this should be 'echo'
fi
done < newcontext
I find the formatting of the code in the question makes it difficult to read, so I will not spend a lot of time verifying that this logic matches yours. It appears that the variable r is totally unused, the sed and the cat seem incorrect...but this gives you the idea.
Also, it might be stylistically cleaner to write the inner portion as:
if test "$var2" = false; then
while read c cc; do
...
done
else
while read var3 var4; do
...
done
...
fi < adaptrules
Note that you need to be careful that none of the commands inside the outer while loop consume anything from stdin. (hence the <&- which closes that file descriptor for sed and cat, which is not strictly necessary in these cases but demonstrates how to ensure that you do not inadvertently consume from the input to the loop.) It's probably cleaner to do things like:
while read -u 5 var1 var2; do
...
done 5< newcontext
the content of text files
my script generates a new configuration (newconfig) using the context data (newcontext), the current configuration and adaptations rules.
You would need to execute the cut command with example:
var1=$(cut -f1 -d " " <<< $i)
You are trying to execute the cut command as if $i contains a filename when it actually contains text.
my script is intended to generate a new configuration (newconfig). this configuration is generated using the context data (new context), adaptations rules (adaptrules) and the current configuration (currentconfig). the script works as follow: for each contextdata (the field var1 in newcontext), we look for its action (the field cc in adaptrules). then we verify if this action is present in the currentconfiguration. then, if the action of the selected contextdata is present in the currentconfig and the field var2 of contextdata is equal to false, then the action is deleted from the currentconfig else if the action is absent in the currentconfig and the var2 of contextdata is equal to true, so the action is added to the currentconfig. I had modified my script but it generated an error "sed, command c expects followed by text".
the new code is as follows
#!/bin/bash
while read var1 var2 ;do
while read c cc;do
if test "$c" = "$var1" ;then
r=$cc
fi
done <adaptrules
exist=false
while read var; do
if test "$var" = "$r";then
exist=true
fi
done < currentconfig
if test "$var2" = false && test "$exist" = true; then
sed -i "/$r/d" currentconfig
fi
if test "$var2" = true && test "$exist" = false; then
echo "$r">> currentconfig
fi
done < newcontext
thank you

How to echo arguments in loop in bash

I have a bash that should be run in this way:
./script.sh <arg1> <arg2> <arg3>...<argn>
I want to show these args in my bash:
<arg3> <arg4> ... <argn>
So I wrote this bash:
for (( i=1; i<=$#-3; i++ ))
do
echo $((3+i))
done
but it shows me number of args.
How can I put # in order to see my real args?
Thanks
If you want to show arguments starting from arg3, you can simply use
echo "${#:3}" # OR
printf "%s\n" "${#:3}"
If you really want to show argument indices, use
for (( i=3; i < $#; i++)); do
echo $i
done
You can store all arguments in a BASH array and then use them for processing later:
args=( "$#" )
for (( i=2; i<${#args[#]}; i++ ))
do
echo "arg # $((i+1)) :: ${args[$i]}"
done
A minimal solution that displays the desired arguments without the math:
shift 2
for word
do
echo ${word}
done
I prefer #anubhava's solution of storing the arguments in an array, but to make your original code work, you could use eval:
for ((i=1;i<=$#;i++)); do
eval echo "\$$i"
done
After your all good answers I found this solution that works well for my thread:
ARG=( $(echo "${#:3}") )
for (( i=1; i<=$#-3; i++ ))
do
echo ${ARG[i]}
done

Bash - Multiple conditions in a for loop

I'm trying to do a for loop with multiple conditions and I didn't find any information about how to do it on the web
I'm sorry for the stupid questions, but I just started programming in linux
what am I doing wrong here?
#!/bin/bash
j=0
for line in `cat .temp_` || j in `seq 0 19`
do
...
done
the error says wrong syntax and that I can't use ||
Thanks a lot
for line in `cat .temp_`
do
if ! grep -Fxq $line $dictionary && [ $j -lt 20 ]
then
echo $line >> $dictionary
j=$((j+1))
fi
[ $j -gt 20 ] && break
done
You can't check a condition in a for loop in shell. You must do it in a extra statement.
In this case so:
[ $j -gt 20 ] && break
Another solution, without break:
while read line && [ $j -lt 20 ]
do
if ! grep -Fxq $line $dictionary && [ $j -lt 20 ]
then
echo $line >> $dictionary
j=$((j+1))
fi
done < .temp_
You are trying to combine two different styles of for-loops into one. Instead, just break if the value of j becomes too large:
j=0
while read -r line; do
[[ j >= 20 ]] && break
...
done < ._temp
(This, by the way, is the preferred way to iterate over a file in bash. Using a for-loop runs into problems if the file is too large, as you essentially building a command line using the entire contents of the file.)
[UPDATE: the following is based on my conjecture as to the purpose of the loop. See Calculate Word occurrences from file in bash for the real context.]
Actually, you can dispense with the loop. You are looking for at most 20 lines from .temp_ that do not already appear in the file whose name is in dictionary, right?
sort -u .temp_ | grep -f $dictionary -Fx -v -m 20 >> $dictionary
This will call grep just once, instead of once per line in .temp_.
A simple nested for-loop?
for line in `cat file`; do for j in {0..19}; do
your_commands
done; done
If I understand you correctly (you want to run a command on every line 20 times).
Once I need to process all files inside a directory, but only until nth file or until all is processed:
count=1
nth=10
for f in folder/*; do
((count++))
# process $f
if [[ $count -gt $nth ]]
then
break
fi
done

shell script to compare files and print formatted output

I'm trying to write a shell script which will compare two files, and if there are no differences between then, it will indicate that there was a success, and if there are differences, it will indicate that there was a failure, and print the results. Here's what I have so far:
result = $(diff -u file1 file2)
if [ $result = "" ]; then
echo It works!
else
echo It does not work
echo $result
fi
Anybody know what I'm doing wrong???
result=$(diff -u file1 file2)
if [ $? -eq 0 ]; then
echo "It works!"
else
echo "It does not work"
echo "$result"
fi
Suggestions:
No spaces around "=" in the variable assignment for results
Use $? status variable after running diff instead of the string length of $result.
I'm in the habit of using backticks for command substitution instead of $(), but #Dennis Williamson cites some good reasons to use the latter after all. Thanks Dennis!
Applied quotes per suggestions in comments.
Changed "=" to "-eq" for numeric test.
First, you should wrap strings being compared with quotes.
Second, "!" cannot be use it has another meaning. You can wrap it with single quotes.
So your program will be.
result=$(diff -u file1 file2)
if [ "$result" == "" ]; then
echo 'It works!'
else
echo It does not work
echo "$result"
fi
Enjoy.
Since you need results when you fail, why not simply use 'diff -u file1 file2' in your script? You may not even need a script then. If diff succeeds, nothing will happen, else the diff will be printed.
bash string equivalence is "==".
-n is non-zero string, -z is zero length string, wrapping in quotes because the command will complain if the output of diff is longer than a single string with "too many arguments".
so
if [ -n "$(diff $1 $2)" ]; then
echo "Different"
fi
or
if [ -z "$(diff $1 $2)" ]; then
echo "Same"
fi

Resources