I have a shell script that runs a for loop to execute a command on multiple text files in a folder. I want to test if these files' names start with a specific set of letters (NA for instance), and have no special characters in the file (no periods except before a file extension, '-'s,'_'s, eg). I know how to test a file's full name, but I don't know how to test if part of it has those characters or how to specify the containing of only letters and numbers but no special characters except for the '.' in '.txt'. How would I go about doing this so that a command executes only on files meeting these requirements? I know it would use an if statement, but other than that I am not sure. It seems like situation to use either wildcards or reg-exs.
The code below will allow you to perform some action on text files starting with "NA", only having alphanumeric characters, and ending in ".txt".
for f in /path/to/your/folder/*; do
if [[ ${f##*/} =~ NA[a-zA-Z0-9]*.txt ]]; then
# perform some action on $f
fi
done
If you want to allow your file to start with "N" or "A" use this:
for f in /path/to/your/folder/*; do
if [[ ${f##*/} =~ [N,A][a-zA-Z0-9]*.txt ]]; then
# perform some action on $f
fi
done
-
-
${f##*/}
is the same as$(basename $f)
but without forking a subprocess.=~
allows for regular expressions. – airfishey Jul 8 '15 at 19:22 -
2You need to remove the comma in
[N,A]
- because that allows for any filename which begins with an N or an A or a comma. Also, this only works properly in a POSIX locale, and, what's more it will not match any filenames containing any hyphens or underscores. – mikeserv Jul 8 '15 at 20:40
Here a fast hack:
#!/bin/bash
for i in *;
do
if [ $(echo $i|cut -c 1-2) == "NA" ];
then
EXECUTE_COMMAND
fi
done
Did I understand your question correct?
You could use extended globbing if your shell supports it, e.g.
bash:
shopt -s extglob
for f in NA*([[:alnum:]]).txt; do something; done
zsh:
setopt extendedglob
for f in NA([[:alnum:]])#.txt; do something; done
where *(...)
and respectively (...)#
mean zero or more occurrences.
-
-
I read it the opposite - like only these kinds. It's really hard to tell, though. You're probably right. – mikeserv Jul 9 '15 at 2:02
for f in ./*
do case ${f#??} in
(*.*.*|*[!-_.[:alnum:]]*) ;;
(NA*.txt)
: do something w/ "$f"
esac
done
The case
statement allows you to branch code blocks for multiple possibilities. Though I make the above match for 2 or more dots or a not-dash-underscore-dot-alphanumeric character a no-op, you're just as free to put a code-block there as you are any other place. case
matches as much as and as soon as it can, and so if you get to the NA*.txt
match it is only because the filename which matches that pattern doesn't also match the pattern which came before.
And as I said, this is a branching statement, and so...
for f in ./*
do case ${f#??} in
(*.*.*|*[!-_.[:alnum:]]*) ;;
(NA*.txt)
: do something w/ "$f.txt";;
(NA*.pdf)
: do something w/ "$f.pdf";;
(FA*.txt)
: do something w/ "$f";;
(*)
: do something w/ everything else
esac
done
...is perfectly valid. Each conditional block can be as you long as you could wish it - and newlines and the rest are valid within them. Every conditional block but the last must be delimited with two semicolons, but these are optional for the last conditional block.
As the case
is evaluated each pattern is evaluated in turn. If a match is found, none of the following patterns are evaluated at all - they are effectively short-circuited in that case.
egrep should do:
egrep 'NA[A-Z a-z 0-9]*\..{3,4}$'
So ls /path/to/dir | egrep 'NA[A-Z a-z 0-9]*\..{3,4}$'
would list:
NAfoo.txt
NAbar1.jpeg
NA123baz.txt
but would exclude:
aiNA1foo.txt
NA2foo_bar.jpeg
NAbar.baz.txt
And so on.
basename
to strip off the extension; useecho $filename | grep ...
for the rest – Jeff Schaller♦ Jul 8 '15 at 19:08