I have a file in the form of:
XXX XXXX XXX-6VwvOkZvzuI.description
How can I get just the file name XXX XXXX XXX
?
I've tried:
for file in $(ls .d*)
do
fname="${file%*-}"
ext="${filename%.*}"
done
I have a file in the form of:
XXX XXXX XXX-6VwvOkZvzuI.description
How can I get just the file name XXX XXXX XXX
?
I've tried:
for file in $(ls .d*)
do
fname="${file%*-}"
ext="${filename%.*}"
done
Do not parse the output of ls
(see e.g. Why *not* parse `ls` (and what to do instead)?). The issue that you're running into is that your loop variable, file
, will take the values of your filenames after they have all been concatenated into a single long string and then split on whitespaces (and after any split-up word that happens to be a globbing pattern has been expanded). You'll get three iterations of your loop for the filename XXX XXXX XXX-6VwvOkZvzuI.description
, for example, one each for the values XXX
, XXXX
, and XXX-6VwvOkZvzuI.description
.
To iterate over all files that have a dash in their names and then a filename suffix of .description
use
for name in *-*.description; do ...; done
To pick out the part before the -
in $name
, use a standard parameter expansion that removes everything after the first -
in the string:
prefix=${name%%-*}
The difference between using %%
and %
here is that with %%
the longest matching tail string is removed. This matters if there happens to be multiple -
characters in any name.
Your loop then becomes
for name in *-*.description; do
prefix=${name%%-*}
done
The filename suffix is already known (.description
), but you can can get the bit of the filename from the -
to the suffix using
infix=${name#"$prefix"}
infix=${infix%.description}
Finally, with a script like
#!/bin/sh
suffix=.description
for name in -"$suffix"; do
prefix=${name%%-*}
infix=${name#"$prefix"}
infix=${infix%.description}
printf 'prefix="%s", infix="%s", suffix="%s"\n' \
"$prefix" "$infix" "$suffix"
done
you'll get
$ ls
XXX XXXX XXX-6VwvOkZvzuI.description XXX XXXX XXX-6VwvOkZvzuK.description
XXX XXXX XXX-6VwvOkZvzuJ.description script
$ ./script
prefix="XXX XXXX XXX", infix="-6VwvOkZvzuI", suffix=".description"
prefix="XXX XXXX XXX", infix="-6VwvOkZvzuJ", suffix=".description"
prefix="XXX XXXX XXX", infix="-6VwvOkZvzuK", suffix=".description"
I'll leave my answer up, but add the warning from @Kusalananda's answer: Do not
parse the output of ls
(see e.g.
Why *not* parse `ls` (and what to do instead)?).
You could pipe the output of ls directly into sed and substitute just the part
coming before the hyphen (-
):
ls *.d* | sed 's/\(.*\)-.*/\1/'
I tried this with two files called:
XXX XXXX XXX-6VwvOkZvzuI (copy).description
XXX XXXX XYZ-6VwvOkZvzuI.description
and the output is:
XXX XXXX XXX
XXX XXXX XYZ
The way the sed command is working is as follows:
\(
and \)
which in this
case is everything up to the last hyphen in the file name (you'd need to
adapt it if your files have later hyphens in the names)\1
- i.e. just the XXX partYou can put the output of the command into a file if needed with:
ls *.d* | sed 's/\(.*\)-.*/\1/' > new_file
ls *.d* | sed 's/\(.*\)\..*/\1/'
, but if you have files like filename.my.ext
that method would return filename.my
– mattb
Jun 20 '21 at 09:52
Try this
$ ls -1
x.sh
XXX XXXX XXX-6VwvOkZvzuI.description
YYY XXXX XXX-6VwvOkZvzuI.description
$ cat x.sh
#!/bin/bash
for file in *.d*
do
fname=${file/-*/}
ext=${file/*-/}
echo fname $fname ext $ext
done
$ ./x.sh
fname XXX XXXX XXX ext 6VwvOkZvzuI.description
fname YYY XXXX XXX ext 6VwvOkZvzuI.description
$