How To Retreive Files With a Special Condition?

Everyday I have to get a list of files in a directory with a special condition and feed this list to a for loop to be processed. Since I do not use Unix all the time, it is tricky for me to get that list of files. So, the question is whether there are commands that will give me the file names with a specific condition. See explanation and example below.

This is what I have to do.

  1. Do ls -l to show all the files
  2. Look for the last file that has a .x at the end
  3. Get all the file names after the last .x files
  4. Type in for x in and then copy-paste each file name separated by a space after the word in

Here is an example:

Type in ls -l and get the following list of files

A1.b.x
A2.d.e.f
A3.g.h.i
A4.j.x
A5.k.l.m
A6.n.o.p

The last file with a .x suffix is A4.j.x

So, the files after the last .x file are:

A5.k.l.m
A6.n.o.p

The for loop command will look like the following. I have to manually copy-paste the file names in.

for x in A5.k.l.m A6.n.o.p Is there a way to get the file name list with a command and then feed/pipe it to the for command?

I apologize if this is not clear. Please let me know if more clarification is needed.

Thank you.

How about

for x in $(ls -r A[0-9]* | awk '/x$/ {exit} 1'); do echo $x; done
A6.n.o.p
A5.k.l.m

Example dir to process

$ ls -1 april/
A1.b.x
A2.d.e.f
A3.g.h.i
A4.j.x
A5.k.l.m
A6.n.o.p
#!/bin/bash
# script name: after_last_x.sh

# Expects the name of the directory to process
# Script lives outside to avoid being included
cd "$1"

# Place holder for files found
fnames=()

# Start processing the list
for f in $(echo *); do
    # Clear the place holder if the marked file is found
    [[ $f =~ x$ ]] && fnames=() && continue
    # Add to place holder after last marked file
    fnames+=("$f")
done
# Display result
printf "%s\n" ${fnames[@]}

Example output:

$ bash after_last_x.sh april/
A5.k.l.m
A6.n.o.p

The simple

for f in *; do

correctly handles filenames with special characters.
Use quotes for correctly printing an array of strings:

printf "%s\n" "${fnames[@]}"

Compare with

for f in "${fnames[@]}"; do echo "$f"; done
for f in "$@"; do echo "$f"; done

The @ lets the shell split on array elements (and parameters) despite the quotes.

Hello RudiC,
I tried to run the command you posted

for x in $(ls -r A[0-9]* | awk '/x$/ {exit} 1'); do echo $x; done

But I got the following error:

/bin/ls: cannot access A[0-9]*: No such file or directory

Thank you for helping.

What OS and ls version? Are you in the right directory? Do any files starting with "A" and a number exist?

Well, here is what I got when I typed in

uname -a
Linux (server name) 3.0.101-108.52-default #1 SMP Tue May 29 19:42:53 UTC 2018 (80e6815) x86_64 x86_64 x86_64 GNU/Linux

As far as the ls version, i do not know how to search for that.

The files do not start with an A. I just happened to pick that as examples. There are numbers imbedded in the file names which are the dates & times the files were received and created.

ls --version

if it is a Gnu ls (which is most likey given your OS)

Please post examples of filenames in the directory. The above solutions are based on your example file names.

Andrew

I wonder if I look at this a little differently.

If I know the name of the last .x file, does it make it easier if I look for all the file names created after that last .x file?

---------- Post updated at 02:39 PM ---------- Previous update was at 02:33 PM ----------

Examples of filenames:

mRefresh_2018-06-28_003015.x
mRefresh_2018-06-28_221609.tar
mRefresh_2018-06-29_003058.tar
mRefresh_2018-06-29_003058.x
mRefresh_2018-06-29_220654.tar
mRefresh_2018-06-30_003043.tar
mRefresh_2018-07-01_222747.tar
mRefresh_2018-07-02_003030.tar

So, based on this list, I want the name of the last 4 files.

ls --version
ls (GNU coreutils) 8.12

Too bad - had my olfactory monitor not collapsed recently, I could have smelled your sample didn't meet your reality, and of course had not mapped your sample data in my proposal.

As it turns out my proposal doesn't apply, please adapt it to meet your request.

Assuming (1) that there are other files in that directory but you are only interested in those that start with mRefresh; and (2) that the timestamp in the filename is the one you should be relying on:

ls -r mRefresh_* | sed '/\.x$/,$ d'

The files will be in reverse order, I'm afraid, but you can fix that if necessary by adding | tac to the pipeline.

Andrew

Hello apmcd47,
Thank you for your post.

All the files in the directory start with mRefresh_
The timestamp doesn't matter to me in my script.
The order doesn't matter to me because I just need to copy them to another directory.
So, your code works for me.

Thank you very much, apmcd47 and all who replied.

Another solution with shell internals, relying on the alphabetic order of the file names

out=""
for f in *
do
  if [[ $f == *.x ]]
  then
    out=""
  else
# append $f to $out (after a newline if $out is not empty)
    out="${out:+$out
}$f"
  fi
done
echo "$out"

This uses a simple shell string as an output buffer,
otherwise it works like the solution with a bash array in post#3 (by Aia, see my corrections in post#4).