59

I have a directory called uploads. It contains a bunch of files, plus a few subdirectories which in turn contain files.

Is there a way I can (in one step) do the following:

  1. List ONLY the files in the root uploads directory -- I do not want to see the subfolder names or their contents;

    and

  2. Do NOT list any files that start with t_

I know about the -d flag, but it doesn't get me quite what I want.

9 Answers 9

68

This sounds like a job for find.

  • Use -maxdepth to only return the current directory, not recursivly search inside subfolders
  • Use -type f to only return files and not directories or device nodes or whatever else
  • Use a combination if -not and -name to avoid the files with names you don't want

It might come together like this:

find /path/to/uploads -maxdepth 1 -type f -not -name 't_*'
2
  • Thanks! I'm pretty new to CLI and had never used find before. I'll definitely look further into it.
    – EmmyS
    Commented Jul 1, 2011 at 17:50
  • 2
    @EmmyS: You might find one more little trick useful here. @Gilles mentioned using -exec ls -lG -- {} + in his answer to get the output using extra options to ls. You can also add just an -ls to this find to get a quick and dirty approximation of ls's detailed view.
    – Caleb
    Commented Jul 2, 2011 at 9:12
20

GNU ls (i.e. the ls command on non-embedded Linux systems and Cygwin, also available on some other unices) has an option to hide some files, based on their names. There's no way to ignore directories though.

ls --hide='t_*' uploads

Another approach is to make your shell do the matching. Bash, ksh and zsh have a negation pattern !(t_*) to match all files except those matching t*; in bash this feature needs to be turned on with shopt -s extglob, and in zsh it needs to be turned on with setopt ksh_glob. Zsh also has the equivalent syntax ^t_* which needs to be turned on with setopt extended_glob. This still doesn't ignore directories. Zsh has an extra feature that allows to match files not only by name but also by metadata and more: glob qualifiers. Add (.) at the end of a match to restrict to regular files. The negation ^ is part of the name matching syntax, so ^t_*(.) means “all regular files not matching t_*” and not “all files that aren't regular files matching t_*”.

setopt extended_glob  # put this in your ~/.zshrc
ls uploads/^t_*(.)

If you find yourself without advanced tools, you can do this on any unix with find. It's not the kind of thing you'd typically type on the command line, but it's powerful and precise. Caleb has already shown how to do this with GNU find. The -maxdepth option isn't portable; you can use -prune instead, to portably stop find from recursing.

find uploads/* -type d -prune -o \! -type f -name 't_*' -print

Replace -print by -exec ls -lG -- {} + to execute ls with your favorite options on the files.

All the commands above hide dot files (i.e. files whose name begins with a .). If you want to display them, pass -A to ls, or add the D glob qualifier in zsh (ls uploads/^t_*(.D)). With find, you can use a different approach of making it recurse one level only (find doesn't treat dot files specially). This only fully works if you run find in the current directory.

cd uploads && find . -name . -o -type d -prune -o \! -type f -name 't_*' -print
10
  • 3
    Do you have a dayjob? ;-) I'm constantly amazed at the length and level of details of your answers, even to the simplest looking questions here at Unix SE!.. Keep that up anyway! :)
    – alex
    Commented Jul 1, 2011 at 19:01
  • Thanks! Great detail. I don't know if I have "advanced tools" or not right now; I'm on a Mac at work (although Linux at home, so I'm sure this will come in handy at some point.)
    – EmmyS
    Commented Jul 1, 2011 at 19:30
  • @EmmyS: For your linux box my use of -maxdepth should work, but the "portability" problem Gilles refers to is that the BSD find (also found on OSX I think) is a bit different animal, so you might need his answer too. @Gilles: +1 for the zsh trick!
    – Caleb
    Commented Jul 1, 2011 at 19:54
  • 1
    @Gilles: Some not so juicy comments about prunes come to mind, but I'll let it go by simply saying that when I'm mucking around on my own systems the number of times the thought "would this command work if I was on AIX, Solaris or MINIX3" is approximately ... standby ... I'm having a hard time getting a meter reading ... the display is frozen with 0.00.
    – Caleb
    Commented Jul 2, 2011 at 9:17
  • 2
    Doesn't Gnu ls have a --use-telepathy option? That's the quickest way to display just the files you want. It might not be portable though.
    – dubiousjim
    Commented Oct 17, 2012 at 18:20
11
ls -l /folder | grep ^- | awk '{print $9}'
4
  • What is $9 in this statement?
    – EmmyS
    Commented Oct 17, 2012 at 17:05
  • 3
    @EmmyS It means the 9th field / column of the output. This answer is trying to parse ls output.
    – jw013
    Commented Oct 17, 2012 at 17:36
  • 1
    print $NF` would be more betterer, IMO. $NF means number of fields, which would be 9 and is a common usage in AWK as good opportunity to teach others about $NF. Commented Aug 6, 2018 at 22:01
  • 1
    @ElijahLynn "More betterer" made my day, I did not know the expression :D
    – Antonio
    Commented Oct 25, 2022 at 11:29
2
ls -l | grep -v ^d | grep name$
2
  • What would make this solution (which requires multiple commands and pipes) preferable to find?
    – HalosGhost
    Commented Oct 3, 2014 at 16:49
  • It is concise, easy to read and stays with the ls command convention. I find it easier to remember than the find command arguments. To each their own and kudos for options!
    – tkjef
    Commented Dec 1, 2016 at 18:36
1

I found these short ways:

ls -p uploads | grep -Ev '/'

or

ls -pIt_* uploads | grep -v /
0

Let me give it a shot using ls and pipes:

ls  -l --hide='t_*'  uploads/ | grep -v ^d | tr -s ' ' | cut -d ' ' -f 9

say last column is the 9th one.

1
  • 1
    What if there are files with spaces?
    – jordanm
    Commented Oct 17, 2012 at 17:52
0

If find's -maxdepth portability issue is a concern, you could use:

ls -l uploads/ | awk '/^-/ && $9 !~/^t_/ {print $9}'

I'm not an expert, but I think this should work. I suppose it looks a little cryptic, but if you speak awk, it's really not. $NF could be used instead of $9. You could also do:

ls -l uploads/ | awk '/^-/' | awk '!/^t_/ {print $9}'

which does the same thing (but perhaps less efficiently than the former ???).

Actually, after thinking about the other posts, it looks like

ls -l --hide=t_* uploads/ | awk '/^-/ {print $9}'

is an even shorter and clearer way.

Someone please correct me if I'm wrong. :-)

2
  • Parsing ls is generally not a good idea. Your awk tricks will fail with filenames with whitespace in them for instance.
    – Mat
    Commented Jun 23, 2013 at 18:53
  • @mat -- Thank you for the correction. After reading the article that you (and jw013) pointed out, I see that ls cannot be trusted to output correct file names. Even if I were to rewrite the awk code to print everything from $9 to the end of the line (to include whitespaces), this ls output may still be erroneous. This is disappointing and should be corrected IMO. Thanks again.
    – kkaszub
    Commented Jun 24, 2013 at 3:37
-1

Try this alias and use it:

alias l='ls -hLlF'
3
  • ls -hLlF does show the subdirectories and it does show the files starting with t_. So how does this answer the question? Commented May 18, 2016 at 7:36
  • Perhaps I misunderstood the question. ls -hLlF will not show the target directories of linked directories.
    – Granular
    Commented May 18, 2016 at 8:59
  • Seems so. But haven't you read the other answers for the question? Commented May 18, 2016 at 11:25
-1

Easy peasy:

ls -l --hide 't_*' <absolute path to desired directory> | grep -v ^d

2
  • (1) This answer is so easy, it’s been given before.  (2) Why do you believe that you need to specify the full path to the directory? Commented Jul 30, 2018 at 20:17
  • @Scott - this is a very quick and simple way to get to the solution. The full path was specified to make the answer universal...
    – Digger
    Commented Jul 31, 2018 at 5:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .