How to Get the Parent Directory of a File in Pure Bash?

0
0
Asked By SilentThunder60 On

I'm trying to find an efficient way to retrieve the parent directory of a file without including the full path in pure Bash. Essentially, I want to extract the substring from a variable that sits between the last two slashes in the path.

I already know how to achieve this with a few steps, such as:
```bash
path='/path/to/parentdir/file'

dirpath="${path%/*}"
pardir="${dirpath##*/}"
echo "$pardir"
```

Or using awk:
```bash
awk -F '/ ' '{sub(//.[^.]+$/, "", $NF); print $(NF-1)}' <<< "$s"
```

There's also the `expr match` method, but I'm not very good with regex. I wonder if there's a simpler, one-step solution purely in Bash to achieve this extraction.

5 Answers

Answered By CodeWhizKid99 On

I'd recommend your first option since it's straightforward. If you're looking to minimize variables, you could do:
```bash
file='/path/to/parentdir/file'
: "${file%/*}"; pardir=${_##*/}
```
Just a heads up—this might throw unexpected results with something like `file=/something/with/extra//slashes//`. For a more refined approach, use this:
```bash
shopt -s extglob
: "${file%%*(/)+([!/])*(/)}"; pardir=${_##*/}
```
This tackles those tricky cases better.

Answered By ShellSavant12 On

It's worth mentioning that you didn't clarify if your path is relative or absolute. But if we assume it's absolute as per your example, you're on the right track. Just remember that directories can end with multiple slashes.
You might also run into an issue with edge cases like the root directory, which is its own parent. Handling all these is a bit complex without going beyond a simple one-step solution, but here's a fancy function to handle it:
```bash
parent(){
[ $# -eq 1 ] || return 1
local p="$1"
[[ "$p" =~ /([^/]+)/ } && printf '%s' "${BASH_REMATCH[1]}" || printf /
}
```

Answered By DigitalNomad42 On

You've got a solid start! You can simplify your one-liner to this:
```bash
pardir="$(basename "$(dirname "path/to/parentdir/file")")"
```
If you want to keep it as one line, try using semicolons to break the commands up instead of new lines.

Answered By RegexGuru77 On

If you're okay with using a tool outside of pure Bash, you could leverage `jc` and `jq` to simplify your process:
```bash
echo '/path/to/parentdir/file.txt' | jc --path | jq -r '.path_list[-2]'
```
This would output just the immediate parent directory. Just to clarify, I actually created `jc` so I'm a bit biased here!

Answered By ScriptingNinja88 On

If you're okay with a slightly longer command, you can use Bash's regex match to extract the parent directory directly:
```bash
[[ $path =~ /([^/]+)/[^/]+$ ]] && dir="${BASH_REMATCH[1]}"
```
Just a note, you don't need to escape the slashes with `` here. If you're looking for pure Bash options, you could also parse the path into an array, but that's a bit more involved.

TechExplorer55 -

Good point! You can indeed use an array to break up the path:
```bash
IFS=/ read -rd '' -a path_components < <(printf '%s' "$path") if (( ${#path_components[@]} > 1 )); then
pardir=${path_components[-2]}
fi
```
Remember, though, normalization is key with paths provided by users.

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.