bash: get path to parent directory by name - bash

I'm trying to get the path to the nearest parent directory named foo:
/this/is/the/path/to/foo/bar/baz
yields
/this/is/the/path/to/foo
Any idea how I do this?

Using BASH string manipulation:
p='/this/is/the/path/to/foo/bar/baz'
name='foo'
r="${p%/$name/*}/$name"
echo "$r"
/this/is/the/path/to/foo
OR better would be to use:
p='/this/is/afoo/food/path/to/foo/bar/baz'
echo "${p/\/$name\/*/\/$name}"
/this/is/afoo/food/path/to/foo
BASH FAQ Reference

Try this: This operation (using % sign) will remove anything after foo word (if it's in a variable var from the right side) then suffix it with foo.
echo ${var%/foo/*}foo
or
echo ${var/\/foo\/*/\/foo}
Removing foo (at last) from the above command will give the parent folder of first occurrence of foo folder. Including foo will give you the first foo folder as the parent.
PS: If there's no "/foo/" folder in the path, then, the above echo command will output whatever is the value of given path (i.e. $var as it's) aka it'll output a wrong output for your purpose OR it may work correctly only in case the given path i.e. $var is /foo).

Related

How to split the path to get the directory in shell script

I am trying to split the path of a file to get the directory name to check if the directory exists in the new location or not using shell script.
I tried using
cf=src/classes/CarExperience.cls
echo ${cf%/*}
echo ${cf##/*/}
echo ${cf#/*/*/}
echo ${cf%/*}
echo $(dirname "$cf")
But none of these are giving me desired result
Desired result is get part after the src and check if that inner directory exists or not.
cf=src/classes/CarExperience.cls
directory_name=classes
Appreciate any help on this regard.
You could do:
full_dir=$(dirname "$cf")
last_dir=$(basename "$full_dir")
or in one shot
last_dir=$(basename "$(dirname "$cf")")
Yes, you want all those quotes.
With shell parameter expansion:
full_dir=${cf%/*}
last_dir=${full_dir##*/}
That one has to be done in 2 steps.
Like this, using parameter expansion as you try to do:
cf=src/classes/CarExperience.cls
cf=${cf#src/*} # become 'classes/CarExperience.cls'
echo ${cf%/*} # become 'classes'
Output
classes

Get the full path of the only file in a directory

I have a directory with a single file. The name of the file is randomized, but the extension is fixed.
myDirectory
|----file12321.txt
Is there a one-line way to extract the full path of that file?
MY_FILE=myDirectory/*.txt
Current output:
/home/me/myDirectory/*.txt
Expected:
/home/me/myDirectory/file12321.txt
Use readlink to get canonized path.
MY_FILE=$(readlink -f myDirectory/*.txt)
If you want only myDirectory/file12321.txt part you could run a command that will let shell expand *, like:
MY_FILE=$(printf "%s\n" myDirectory/*.txt)
If it's certain that there is exactly one file, you can just use an array:
MY_FILE=( /home/me/myDirectory/*.txt )
Filename expansion takes place inside an array definition but not when setting the value of a normal variable. And you can just use the array like a normal variable, as that will provide the value of the first element:
$ foo=(1 2 3)
$ echo "$foo"
1
MY_FILE=$(pwd)/$(ls myDirectory/*.txt)
# $MYFILE == /home/me/myDirectory/file12321.txt

Shell Script: Add a character in a variable

Id like to add a character a variable.
I have a file path y/photos/family/kids.jpg.
Its currently assigned to a variable $kidsReal
Id like it to be Y:/photos/family/kids.jpg
(It needs to recognize the photos are coming from the Y drive (Y:)
So far I have (??? is where I am stuck):
#!/bin/bash
#find the kids.jpg back one directory and into the family directory
kids=$(find .. -type f -path *family*/* -name *kids.jpg)
#convert to absolute path
kidsReal=$(realpath ${kids})
#add : between y and / to complete path
kidsRealMod= ???
At the end of the day this variable just needs to be read as a file path to be inserted into a command that will also be coded into the script.
Thank you and please let me know if there are any other details needed for this simple problem.
With bash and a regex:
kidsReal='y/photos/family/kids.jpg'
[[ "$kidsReal" =~ (.)(.*) ]] && kidsRealMod="${BASH_REMATCH[1]^}:${BASH_REMATCH[2]}"
echo "$kidsRealMod"
^ converts first character in a variable to upper-case.
Output:
Y:/photos/family/kids.jpg
See: The Stack Overflow Regular Expressions FAQ
Also, you can split your string into two parts by using ${str:from:to} and join it again with ':'.
str="Y/photos/family/img.png";
new_str=${str:0:1}:${str:1}
echo $new_str
Output:
Y:/photos/family/img.png

shell script error in unix

what does using 1# for a directory do here?
cpfile=${1#/usr/newconfig} ls -l $cpfile | read var1 echo var1
I am tryiing to understand the script, but I cannot find any resource that would help me ascertain the meaning of this command.
In general, variables can be modified with #, which removes a leading string. If a is a variable with content foobar, then ${a#foo} strips the foo and evaluates to bar. In your case, $1 is a positional parameter, and ${1#/usr/newconfig} is the value of that string with "/usr/newconfig" removed from the start. If it does not match, the expression evaluates to the same string as $1.
However, this script has a rather significant issue in that it assigns cpfile in the environment of the ls that is run, but ls does not receive it as an argument. As a result, ls is going to operate on the current working directory rather than the directory passed as an argument to the script. (unless cpfile is assigned previously in the script somewhere.)

how to filter a command subsitution from the resulting value of a readlink for symlink?

This may be poorly titled as I'm not fully sure what the process is called.
Basically I want to get only the last part of a symlink path, and I'm trying to use the same method I use with PWD.
For example:
if I do
PWD
it prints
/opt/ct/mydir
if I do
echo ${PWD##*/}
it prints only the last part
mydir
So using that design I can do
readlink mysymlink
which gives
/opt/ct/somedir
and I can do
TMP=$(readlink mysymlink)
echo ${TMP##*/}
and it will print
somedir
So now how can I combine that last part into one line like
TMP=$(readlink mysymlink && echo ${TMP##*/})
???
The example I show gives me 2 concatenated results.. one with the full path and one with just the part I want. I only want that last directory.
I also tried
TMP=${ $(readlink mysymlink)##*/}
to no avail
Variable substitution suffixes can only be used with variables, not command substitutions. You either have to set the variable and modify it in separate statements, as in your first attempt, or use additional command substitutions:
TMP=$(basename $(readlink))

Resources