I'm trying to list all files in a sub-directory without their path, I just want the file name and extension, but Bash substitution doesn't work with all paths in an array, it only works with the first element.
Code:
#!/usr/bin/bash
NAME="$(pwd | grep -o '[^/]*$')"
# ls src -R
PATH="$(ls src/*.{cpp,hpp} 2> /dev/null)"
if [ 0 -eq "${#PATH[@]}" ]; then
echo "The project has no source code file yet."
exit 0
fi
EMPTY=''
for FILE in "${PATH[@]}"; do
echo "${FILE/src\//$EMPTY}"
done
Directory tree:
FileReader
├── bin
├── make.sh
├── obj
└── src
├── FileReader.cpp
├── FileReader.hpp
└── main.cpp
Expected:
$ bash make.sh
FileReader.cpp
FileReader.hpp
main.cpp
Output:
$ bash make.sh
FileReader.cpp
src/FileReader.hpp
src/main.cpp
Since parsing ls
is bad, I'd do something like:
#!/usr/bin/env bash
# If no matching files, globs expand to an empty string instead of the pattern
shopt -s nullglob
declare -i count=0
for file in src/*.[ch]pp; do
count+=1
printf "%s\n" "$(basename "$file")"
done
[[ $count -eq 0 ]] && echo "The project has no source code file yet."
to avoid issue with funny characters in filenames. basename(1)
removes leading directory components from a filename (And optionally a given extension).
You can also safely get the files in an array with files=( src/*.[ch]pp )
and use something closer to your original approach. I would definitely avoid calling a variable PATH
though as that conflicts with a built in one, though.
Array based version (This one uses the ${variable#pattern}
parameter expansion syntax that strips the matched text of a pattern from the beginning of the variable's value):
#!/usr/bin/env bash
shopt -s nullglob
files=( src/*.[ch]pp )
if [[ "${#files[@]}" -eq 0 ]]; then
echo "The project has no source code file yet."
else
printf "%s\n" "${files[@]#*/}"
fi