0

I'm new to bash, but I had to write a simple script to archive things:

ARCHIVE_FOLDER=".archive/"
TO_ARCHIVE="folders.txt"
TO_IGNORE="ignore.txt"

mkdir -p $ARCHIVE_FOLDER

while read t_arc; do
    EXCLUDE_STRING=" "
    while read ig_l; do
        while read found_exc; do
            EXCLUDE_STRING="${EXCLUDE_STRING} --exclude ${found_exc}"
        done < find $t_arc -name $ig_l
    done < TO_IGNORE
    tar -czf "${ARCHVE_FOLDER}/${t_arc}.tar.gz"
done < TO_ARCHIVE

It looks quite simple, but I get syntax error when using variables which are defined in "while read" construction:

./archive.sh: line 12: syntax error near unexpected token `${t_arc}'
./archive.sh: line 12: `        done < find ${t_arc} -name ${ig_l}'

Apparently, I can't even print them:

while read t_arc; do
    EXCLUDE_STRING=" "
    printf "%s\n" $t_arc # prints noting

What am I doing wrong here?

1
  • 1
    There are 3 read's from that script, you will need to use a different fd for the 2 of them. Also add a shebang and paste your script at shellcheck.net for more help Commented Apr 3, 2021 at 16:33

1 Answer 1

2

The symbol after < is simply a file name. If you want to use a process substitution, the syntax for that is

done < <(find ...)

Alternatively, you can run

find ... |
while read -r ...

(Probably also change your other read statements into read -r unless you specifically require the weird legacy POSIX behavior around backslashes in the input to read.)

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

5 Comments

That works, but isn't <(find ...) construction supposed to write things to file? Are we writing to non-existent file and then reading the same thing in your example?
"Write things to file?" No, that's not at all what it does. Try cat < <(echo hello) for a simple demonstration.
But if < revives a file name, and <(find...) is definitely not a file name (as well as hello string which echo returns in your example), how does it work?
It's called a process substitution. The syntax <(command) basically creates a temporary file handle (something like /dev/fd/63) and runs the background subprocess command with its standard output connected to this file handle.
These syntax extensions aren't always entirely logical because Bash (or often originally Ksh) had to preserve backwards compatibility to the classic Bourne shell when introducing syntax extensions. Thus they had to find places where the syntax didn't already mean something else. I'm personally not very fond of process substitutions, though they can definitely simplify processing sometimes.

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.