1

PROBLEM:

I can't get the $@ variable to do what I want in a for loop, the loop only sends one name into the file while looping, it should loop through all the arguments and write them to the file USERS.txt each on its own line.

Here is the file:

something78
something79
something7
dagny
oli
bjarni
toti
stefan_hlynur
jessie

Here is the test code:

#!/bin/bash

prepare_USERS()
{
    /usr/bin/awk -F: '$3 >= 1000 { print $1 }' /etc/passwd > USERS.txt
    /bin/chmod 777 USERS.txt
    echo "$@"
    for user in "$@"
    do
        echo $user
        echo "$user" >> USERS.txt || echo "writing to USERS.txt failed"; exit 127
    done
}

prepare_USERS "$@"

#for user in "$@"
#do
#    echo "$user" >> USERS.txt
#done

for user in USERS.txt
do
    printf "%s" $user
done

Here are the arguments I pass:

./somethingDELETEme.sh jessie henry allison jason

CURRENT output:

$./somethingDELETEme.sh jessie henry allison jason
jessie henry allison jason
jessie

EXPECTED output:

The loop loops through all names from the argument list and writes it to the file USERS.txt.

QUESTION:

I have used this variable ($@) before and never had this problem.

Why is the loop not iterating through all names in the argument list ($@) and how is the right way coding this?

HERE IS THE REAL CODE:

prepare_USERS()
{
    checkIfUser
    /usr/bin/awk -F: '$3 >= 1000 { print $1 }' /etc/passwd > "$CURRENTDIR"/USERS.txt

    /bin/chmod 777 "CURRENTDIR"/USERS.txt
    for user in "$@"
    do
        echo "$user" >> "CURRENTDIR"/USERS.txt || echo "writing to USERS.txt failed"; exit 127
    done
}
  • Pls be aware that mode 777 (= including execute permission) on a pure data file is unnecessary and may be a security risc. Make up your mind WHO should write that file, and WHO should read it. 600 or 640 may be sufficient. – RudiC Oct 18 '18 at 9:41
3

The problem is with the incorrect usage of exit 127 in your for loop, which is exiting after the first for-loop iteration. You need to group the echo statement and the exit as a compound block under {..} to prevent this.

echo "$user" >> USERS.txt || { echo "writing to USERS.txt failed"; exit 127; }

Without this grouping what happens is the || defined applies only for the echo command and always run the exit command no matter if re-direction to file passed or failed because you have a command separator ; defined there.

Now with the compound grouping enabled, the entire set of actions inside {..} is treated as one block and both of them are executed if the write action to USERS.txt fails.

  • Why isn't this a problem in my code: /bin/chmod 644 "$HOME/.bashrc" || echo "chmod failed"; exit 127 – somethingSomething Oct 18 '18 at 7:25
  • 1
    It isn't a problem, it will run the exit command always, the scope of || ends with the echo "chmod failed". Since you have ; after that, calling exit would return from function/terminal or script depending on where you run it – Inian Oct 18 '18 at 8:32
  • 2
    Or write it as an if statement: if ! echo "$user" >> USERS.txt; then echo "failed..."; exit 127; fi The effect is the same, but some might find the if clearer to read. – ilkkachu Oct 18 '18 at 9:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.