Reputation: 5450
I have filepaths of the form:
../healthy_data/F35_HC_532d.dat
I want to extract F35_HC_532d
from this. I can remove prefix and suffix from this filename in bash as:
for i in ../healthy_data/*; do echo ${i#../healthy_data/}; done # REMOVES PREFIX
for i in ../healthy_data/*; do echo ${i%.dat}; done # REMOVES SUFFIX
How can I combine these so that in a single command I would be able to remove both and extract only the part that I want?
Upvotes: 2
Views: 3179
Reputation: 49
In your specific example the prefix stems from the fact that the files are located in a different directory. You can get rid of the prefix by cd
ing in this case.
(cd ../healthy_data ; for i in *; do echo ${i%.dat}; done)
The (
parens)
invoke a sub shell process and your current shell stays where it is. If you don't want a sub shell you can cd
back easily:
cd ../healthy_data ; for i in *; do echo ${i%.dat}; done; cd -
Upvotes: -1
Reputation: 827
If you are on zsh
, one way to achieve this without the need for defining another variable is
for i in ../healthy_data/*; do echo "${${i#../healthy_data/}%.dat}"; done
This removes prefix and suffix in one step.
Upvotes: 0
Reputation: 3646
You can't strip both a prefix and suffix in a single parameter expansion.
However, this can be accomplished in a single loop using parameter expansion operations only. Just save the prefix stripped expansion to a variable and use expansion again to remove its suffix:
for file in ../healthy_data/*; do
prefix_stripped="${file##*\/healthy_data\/}"
echo "${prefix_stripped%.dat}"
done
Upvotes: 0
Reputation: 157967
If all files end with .dat
(as you confirmed) you can use the basename
command:
basename -s .dat /path/to/files/*
If there are many(!) of those files, use find
to avoid an argument list too long error:
find /path/to/files -maxdepth 1 -name '*.dat' -exec basename -s .dat {} +
For a shell script which needs to deal if any number of .dat
files use the second command!
Upvotes: 1
Reputation: 20002
Do you count this as one step?
for i in ../healthy_data/*; do
sed 's#\.[^.]*##'<<< "${i##*/}"
done
Upvotes: 0
Reputation: 85580
If you can use Awk
, it is pretty simple,
for i in ../healthy_data/*
do
stringNeeded=$(awk -F/ '{split($NF,temp,"."); print temp[1]}' <<<"$i")
printf "%s\n" "$stringNeeded"
done
The -F/
splits the input string on /
character, and $NF
represents the last field in the string in that case, F35_HC_532d.dat
, now the split()
function is called with the de-limiter .
to extract the part before the dot
.
The options/functions in the above Awk
are POSIX
compatible.
Also bash
does not support nested parameter expansions, you need to modify in two fold steps something like below:-
tempString="${i#*/*/}"
echo "${tempString%.dat}"
In a single-loop,
for i in ../healthy_data/*; do tempString="${i#*/*/}"; echo "${tempString%.dat}" ; done
The two fold syntax here, "${i#*/*/}"
part just stores the F35_HC_532d.dat
into the variable tempString
and in that variable we are removing the .dat
part as "${tempString%.dat}"
Upvotes: 1
Reputation: 785126
You can use BASH regex for this like this and print captured group #1:
for file in ../healthy_data/*; do
[[ $file =~ .*/([_[:alnum:]]+)\.dat$ ]] && echo "${BASH_REMATCH[1]}"
done
Upvotes: 5