You are not logged in.

#1 2015-07-31 17:03:00

null
Member
Registered: 2009-05-06
Posts: 398

[solved] Bash: weird variable behaviour

Hi,

I wrote the following script to create an addressbook in the form

Name 1 <Email 1>
..
Name n <Email n>

from vcf files to be used by dmenu.

Here is what I came up with:

#!/usr/bin/bash


ADDRESSES="file_1.vcf ... file_n.vcf" 

for a in $ADDRESSES; do
	IFS=$'\n'
	for line in $(egrep '(^EMAIL|^FN)' $a); do
		case $line in
			FN*)
				name=$(echo $line | cut -d':' -f2)
				;;
			EMAIL*)
				mail=$(echo $line | cut -d':' -f2)
				echo "$name"
				echo "$mail"
				;;
		esac
	done
done

Which works perfectly fine and prints

Name 1
E-Mail 1
...
Name n
E-Mail n

as expected. But if I replace the two echo lines with just

echo "$name $mail"

the output always is just a space and the email address. It seems like, $name just became empty but it really doesn't make any sense for me. Do you know the answer?

Last edited by null (2015-07-31 17:18:26)

Offline

#2 2015-07-31 17:10:34

Vain
Member
Registered: 2008-10-19
Posts: 179
Website

Re: [solved] Bash: weird variable behaviour

I'm pretty sure your .vcf files contain DOS line endings (i.e., CR LF). This means there's a CR at the end of $name which returns the cursor to the beginning of the line. As a result, $mail overwrites $name when printed directly to a terminal.

Offline

#3 2015-07-31 17:18:08

null
Member
Registered: 2009-05-06
Posts: 398

Re: [solved] Bash: weird variable behaviour

Year. Just figured it out myself. Solved by applying

sed 's/\r$//'

after the egrep.

But thanks smile

Offline

#4 2015-07-31 17:30:26

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,534
Website

Re: [solved] Bash: weird variable behaviour

FWIW, that entire loop and everything in it could be replaced by awk:

awk -F ':' '
	/^FN/ { name=$2; }
	/^EMAIL/ { mail=$2; }
	/^END:VCARD/ { printf "%s %s\n", name, mail; }
' $ADDRESSES

"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#5 2015-07-31 18:01:46

null
Member
Registered: 2009-05-06
Posts: 398

Re: [solved] Bash: weird variable behaviour

It probably can, but not by your script. One of the *.vcf files is the sync of my mobile phone and got a lot of contacts without mail addresses and also a few contacts with serveral addresses. Your script doesn't produce anything remotely usefull for me. But I would welcom a working awk solution big_smile

Offline

#6 2015-07-31 18:07:32

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,534
Website

Re: [solved] Bash: weird variable behaviour

It should do the same thing as yours: it finds every line starting with FN or EMAIL and is stores what comes after FN in "name" and what comes after EMAIL as "mail".  The one thing I changed was that it wait's for a line starting with END:VCARD before it prints the pair.  It could just print them in the EMAIL block and it would exactly duplicate the behavior of your script:

awk -F ':' '
	/^FN/ { name=$2; }
	/^EMAIL/ { printf "%s %s", name, $2; }
' $ADDRESSES

But I'm just guessing here as I don't have the input.  The point remains that awk just seems like a much cleaner approach.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#7 2015-07-31 18:48:31

null
Member
Registered: 2009-05-06
Posts: 398

Re: [solved] Bash: weird variable behaviour

I don't really know awk so I can only guess but doesn't you solution lack the overwriting of $name? Because FN always comes before EMAIL I always write the most recent name into $name and only use it, if I get one or more email addresses.
Your first solution seems to always print the last e-mail address for every new contact without email address:

# awk -F ':' '
	/^FN/ { name=$2; }
	/^EMAIL/ { mail=$2; }
	/^END:VCARD/ { printf "%s %s\n", name, mail; }
' addresses.vcf | wc -l
100
# egrep -c '^FN:' addresses.vcf
100
# egrep -c '^EMAIL;' addresses.vcf
35
# ./myscript.sh | wc -l
35

Your second solution doesn't print anything for me.

While I agree that awk seems like a much cleaner approach I did it in bash because I just wanted it to work quickly and I find awk code rather hard to write and to read if it comes to things like 'save the most recent name and print it with every email address until next name'..

Last edited by null (2015-07-31 18:51:35)

Offline

#8 2015-07-31 19:25:12

2ManyDogs
Forum Fellow
Registered: 2012-01-15
Posts: 4,645

Re: [solved] Bash: weird variable behaviour

Trilby wrote:

But I'm just guessing here as I don't have the input.

This. Trilby is trying to help; you could learn awk, give us the input so we could do it for you, or do it with your script if it works for you. In any event this back-and-forth as it is doesn't really help, IMO.

Offline

#9 2015-07-31 21:34:57

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,534
Website

Re: [solved] Bash: weird variable behaviour

null wrote:

While I agree that awk seems like a much cleaner approach I did it in bash because I just wanted it to work quickly and I find awk code rather hard to write and to read if it comes to things like 'save the most recent name and print it with every email address until next name'..

Then go with what works.  I just love awk - and I have a bit of OCD when it comes to scripting: I hate wasted processes.  But in reality this is just pointless OCD as little scripts like this aren't really resource-critical.


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#10 2015-08-01 08:17:35

null
Member
Registered: 2009-05-06
Posts: 398

Re: [solved] Bash: weird variable behaviour

2ManyDogs wrote:
Trilby wrote:

But I'm just guessing here as I don't have the input.

This. Trilby is trying to help; you could learn awk, give us the input so we could do it for you, or do it with your script if it works for you. In any event this back-and-forth as it is doesn't really help, IMO.

I thought it was obvious that I was satisfied with my script but would welcome a working awk solution (because yeah. I also prefere one process to many for the same job).
Which doesn't mean that I want to learn awk right now nor that I want to share private *.vcf files or create new ones with the same structure..

Thanks @Trilby for your input smile



Edit: two years later:

awk -F ':' '/^(EMAIL|FN)/{gsub(/\r$/, ""); if ($1=="FN") n=$2; else print n,$2 }' $FILE

does the trick..

Last edited by null (2018-01-04 20:21:58)

Offline

Board footer

Powered by FluxBB