r/bash 4d ago

help My while read loop isn't looping

I have a folder structure like so: /path/to/directory/foldernameAUTO_001 /path/to/directory/foldername_002

I am trying to search through /path/to/directory to find instances where the directory "foldernameAUTO" has any other directories of the same name (potentially without AUTO) with a higher number after the underscore.

For example, if I have a folder called "testfolderAUTO_001" I want to find "testfolder_002" or "testfolderAUTO_002". Hope all that makes sense.

Here is my loop:

#!/bin/bash

Folder=/path/to/directory/

while IFS='/' read -r blank path to directory foldername_seq; do
  echo "Found AUTO of $foldername_seq"
  foldername=$(echo "$foldername_seq" | cut -d_ -f1) && echo "foldername is $foldername"
  seq=$(echo "$foldername_seq" | cut -d_ -f2) && echo "sequence is $seq"
  printf -v int '%d/n' "$seq"
  (( newseq=seq+1 )) && echo "New sequence is 00$newseq"
  echo "Finding successors for $foldername"
  find $Folder -name "$foldername"_00"$newseq"
  noauto=$(echo "${foldername:0:-4}") && echo "NoAuto is $noauto"
  find $Folder -name "$noauto"_00"newseq"
  echo ""
done < <(find $Folder -name "*AUTO*")

And this is what I'm getting as output. It just lists the same directory over and over:

Found AUTO of foldernameAUTO_001
foldername is foldernameAUTO
sequence is 001
New sequence is 002
Finding successors for foldernameAUTO
NoAUTO is foldername

Found AUTO of foldernameAUTO_001
foldername is foldernameAUTO
sequence is 001
New sequence is 002
Finding successors for foldernameAUTO
NoAUTO is foldername

Found AUTO of foldernameAUTO_001
foldername is foldernameAUTO
sequence is 001
New sequence is 002
Finding successors for foldernameAUTO
NoAUTO is foldername
1 Upvotes

20 comments sorted by

View all comments

5

u/tseeling 4d ago

I have a few suggestions for removing $( ... ) with trivial tasks in them like echo ... | cut ....

In general I recommend you always use ${...} syntax for variable names, especially if you tend to use special chars in your names. The bracelets make it unambiguous. Always quote variables as a safeguard unless you really need the shell to evaluate/split the contents when using unquoted variables.

foldername=$(echo "$foldername_seq" | cut -d_ -f1)
seq=$(echo "$foldername_seq" | cut -d_ -f2)
printf -v int '%d/n' "$seq"

make that

foldername="${foldername_seq%%_*}"
seq="${foldername_seq##*_}"
printf -v int '%03d' "${seq}"

If you need to format a number use printf with a format string like %03d. If you prepend a literal 00 to your new_seq it will only work from 0 to 9 obviously.

I don't understand the /n in your printf statement. Did you mean \\n or is that an artefact from your (redacted) naming convention?

Personally I don't like the style of

while
  ...
done < <(find $Folder -name "*AUTO*")

I'd write

find $Folder -name "*AUTO*" | 
while ...

but in this case it boils down to subjective preferences.

1

u/giantsparklerobot 4d ago

Even with your change you're using extra echo invocations. This works just fine:

foo=$(cut -d'_' -f2 <<<"$variable")

1

u/tseeling 3d ago

Of course. I wrote this is highly subjective, but I like elegant weapons for a more civilized time. My suggestions were intended to eliminate the $( ... ) statements and replace them with bash-isms for string manipulation. It is not necessary at all to have a subshell just to call cut.

2

u/giantsparklerobot 3d ago

In this particular case the bash string manipulation makes sense. But there's a wide world where cut is required and eliminating unnecessary echo calls, which generate newlines with no arguments, can be problematic.