1

I want to sort files into folders based on two conditions, but it won't evaluate both conditions. The conditions are based on values read in from a text file (index.txt) that correspond to the particular subject, and values are coded as 0 or 1

Subid   DX    SEX
XXXX    0      0
YYYY    1      0

the code is as follows

    #!/bin/sh 
    d=XXXX
    dx=$(awk '{if($1=='$d'){print $2}}' index.txt)
    sex=$(awk '{if($1=='$d'){print $3}}' index.txt)
    if [ "$dx" == "0" ] && [ "$sex" == "0" ];then
     commands
    fi

I have tried using double brackets [[ <condition 1> ]] && [[ <condition 2> ]];, collapsing brackets if [ <condition1> && <condition2> ];, parentheses, and using -eq instead of ==, but they still are not evaluating and no errors are being printed. What am I missing?

5
  • 2
    Where are $x and $y set? As you show it, they're going to be the empty string. Commented Dec 4, 2019 at 21:17
  • 2
    Use =, not ==, with [ ... ]. Commented Dec 4, 2019 at 21:19
  • Note that the shell is evaluating the first condition; it's just finding that "" (because x is undefined) does not equal "0", and so && prevents the second condition from being evaluated. Commented Dec 4, 2019 at 21:21
  • edited to show the variables. Unfortunately using a single = didn't do it Commented Dec 4, 2019 at 21:27
  • 2
    Running your code with the file you provided (index.txt), your $dx and $sex variables are empty Commented Dec 4, 2019 at 21:29

2 Answers 2

2

One of the most useful tricks when debugging a shell script is set -x (or running the entire script with sh -x). This makes the shell print the equivalent of each command as it executes them, so you can get a better idea what's actually happening and whether it matches what you expect. Let's try it on your script:

$ sh -x reader.sh
+ d=XXXX
++ awk '{if($1==XXXX){print $2}}' index.txt
+ dx=
++ awk '{if($1==XXXX){print $3}}' index.txt
+ sex=
+ '[' '' == 0 ']'

Note that it set both dx and sex to the empty string. And if you look at the awk script that's being executed, you can see why: XXXX doesn't have double-quotes around it, so awk is treating it as a variable name, rather than a literal string to match against.

You could add double-quotes, but that's not really the best way to do it; sticking literal strings into executable code (an awk script in this case) risks parts of the strings being mistaken for executable code, which can have really weird/bad consequences. The better way to do this sort of thing is to pass the data around as data, by using awk's -v option to set a variable, and then using that. Something like:

$ awk -v d="XXXX" '{if($1==d){print $2}}' index.txt
0

Hey, it printed the right thing! So here's a version of your script using that:

#!/bin/sh
d=XXXX
dx=$(awk -v d="$d" '{if($1==d){print $2}}' index.txt)
sex=$(awk -v d="$d" '{if($1==d){print $3}}' index.txt)
if [ "$dx" = "0" ] && [ "$sex" = "0" ];then
    commands
fi

Note that the awk variable named d has no intrinsic connection to the shell variable named d; the -v d="$d" bit copies the shell variable into the same-named awk variable. Also, I switched the == to just = in the comparison, since that's the standard string-equal operator inside [ ]. bash allows == as a synonym, but not all shells do this; if you're writing specifically for bash, you should use a specific bash shebang line (#!/bin/bash or #!/usr/bin/env bash) rather than #!/bin/sh.

(Actually, I'd recommend using a bash shebang, because if you're not clear on what's standard shell syntax and what's a bash extension, you probably aren't writing portably anyway, so explicitly requesting bash is safer. And if you're doing that, you might as well switch to [[ ]] instead of [ ], because it avoids many of the syntactic oddities that [ ] expressions suffer from.)

Sign up to request clarification or add additional context in comments.

1 Comment

It was reading in my awk syntax fine but I ran sh -x and saw that windows added those invisible carriages to the lines in index and thats why. Thanks alot!
0

The problem is not with your conditions but with your variables set with awk.

Try the following to set your variables:

#!/bin/sh
d=XXXX
dx=$(awk '{if ($1 ~ /'$d'/) print $3}' index.txt)
sex=$(awk '{if ($1 ~ /'$d'/) print $3}' index.txt)
if [ "$dx" = "0" ] && [ "$sex" = "0" ];then
echo "works"
fi

3 Comments

Using == instead of = limits the implements of /bin/sh that this code will work with. The POSIX test specification only defines =, and implementations that do not support == (always report an error and return false when it's used) are not uncommon. See [: Unexpected operator in shell programming.
(To clarify what I mean by "not uncommon" -- think "installed out-of-the-box on Ubuntu").
Thank you @CharlesDuffy, corrected my answer to be POSIX compliant.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.