Get the full path of the only file in a directory - bash

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

Related

Bash: Combine creating a file and storing the Path in a variable

Is there a way to create a file and store the path into a variable in Bash?
ENV_FILE=./.projects.env
echo > $ENV_FILE
How can I achieve this in one command?
Edit:
From the suggestions in the comments below, it could be done like so:
ENV_FILE=$(> ./.projects.env && echo './.projects.env')
If ENV_FILE is not already set, you can use this:
echo > "${ENV_FILE:=./.projects.env}"
Note: if ENV_FILE is already set to a non-null value, this will leave it unchanged and use its existing value. From the Parameter Expansion section of the bash man page:
${parameter:=word}
Assign Default Values. If parameter is unset or null, the expansion of word is assigned to parameter. The value of
parameter is then substituted. Positional parameters and special
parameters may not be assigned to in this way.
BTW, using echo this way will not fully erase the file, it'll replace its contents with a newline (essentially, a single blank line). For a truly empty file, just don't use any command:
> "${ENV_FILE:=./.projects.env}"
You can try
FILE_NAME=<a file name>
ENV_FILE=$(touch "$FILE_NAME" && realpath "$FILE_NAME")
replace <a file name> with the the name you want to give.
if you don't want to repeat the filename (and eliminate potential typos), you can do this instead...
ENV_FILE=$(> ./.projects.env && echo !$)

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

bash: get path to parent directory by name

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).

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))

Call script on all file names starting with string in folder bash

I have a set of files I want to perform an action on in a folder that i'm hoping to write a scipt for. Each file starts with mazeFilex where x can vary from any number , is there a quick and easy way to perform an action on each file? e.g. I will be doing
cat mazeFile0.txt | ./maze_ppm 5 | convert - maze0.jpg
how can I select each file knowing the file will always start with mazeFile?
for fname in mazeFile*
do
base=${fname%.txt}
base=${base#mazeFile}
./maze_ppm 5 <"$fname" | convert - "maze${base}.jpg"
done
Notes
for fname in mazeFile*; do
This codes starts the loop. Written this way, it is safe for all filenames, whether they have spaces, tabs or whatever in their names.
base=${fname%.txt}; base=${base#mazeFile}
This removes the mazeFile prefix and .txt suffix to just leave the base name that we will use for the output file.
./maze_ppm 5 <"$fname" | convert - "maze${base}.jpg"
The output filename is constructed using base. Note also that cat was unnecessary and has been removed here.
for i in mazeFile*.txt ; do ./maze_ppm 5 <$i | convert - `basename maze${i:8} .txt`.jpg ; done
You can use a for loop to run through all the filenames.
#!/bin/bash
for fn in mazeFile*; do
echo "the next file is $fn"
# do something with file $fn
done
See answer here as well: Bash foreach loop
I see you want a backreference to the number in the mazeFile. Thus I recommend John1024's answer.
Edit: removes the unnecessary ls command, per #guido 's comment.

Resources