Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash programming: get name of one-and-only subfolder of given directory

Tags:

bash

In bash, I'd like to get the name of the one-and-only subfolder of a:

cd /tmp; mkdir -p a/b; v=$(ls -1 a); echo "$v"

outputs:

b

Which is what I wanted.

This works, because I know there will be only one-and-only subfolder inside a.

Feel free to assume this is guaranteed in all cases in my scenario.

What I feel uneasy about, is this recommendation from Bash pitfalls

In addition to this, the use of ls is just plain unnecessary.
It's an external command whose output is intended specifically
to be read by a human, not parsed by a script.

This is even more intimidating and lapidary (from the same link as above):


parsing the output of ls -- a utility whose output should never ever be parsed.


It resonates with me but this, an attempt at using bash globbing, obv. does not work:

 cd /tmp; mkdir -p a/b; v=a/*; echo "$v"

outputs:

a/*

Sadness.

So, how can I get globbing for a variable assignment?

I think I know how to leverage globbing outside of assignment..

for d in a/*; do echo "$(basename $d)"; done

outputs:

b

"The right answer" (TM).

Could you kindly teach me how to do this right and explain the principle behind it too, please?

** NOTE: I don't like the output of this command:**

cd /tmp; w='name with blanks'; mkdir -p "$w/b"; v=$(echo "$w"/*); echo "$v"

which is:

name with blanks/b

I'd like to just get:

b

do I have to use basename afterwards, or could I get b directly, somehow?

like image 475
Robottinosino Avatar asked Feb 17 '23 22:02

Robottinosino


1 Answers

Pretty sure I wrote that pitfalls sentence. Anyway... yours fails because brace expansions, globs, and word-splitting don't apply to scalar assignments.

printf -v v %s */

And a little-known trick that will only work using the coreutils printf(1) (assuming there were multiple directories).

v=$(LC_COLLATE=C; /usr/bin/printf '%s\c' */)

Or alternatively, this is probably closest to what you're after (GNU find):

v=$(find . -maxdepth 1 -type d -name '[^.]?*' -printf %f -quit)

See also: http://mywiki.wooledge.org/ParsingLs

like image 50
ormaaj Avatar answered May 07 '23 06:05

ormaaj