Linux - GeneralThis Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
So my boyfriend's GSI for one of his classes told him there's a way you can use ls (not find) to list filenames one-per-line, in BASH without including directories. I think he was either wrong or making that up. There is a way to list just the names and one per line but there aren't any arguments I can find that can be used to exclude directories.
Anyone have a clue? Here's the only way I've been able to do it thus far but apparently isn't what he meant:
Code:
IFS=', '; files=`ls -m`; for i in $files; do if [ -f $i ]; then echo $i; fi; done
That does only use ls as a command, however he said his GSI thought he could do it without all that...
Could it be something like ls -1 (<-this is the number 1) */ This lists the directory contents one per line and only shows the directory name where the files reside.
It's these little "puzzles" that aggravate me. The "solution" never matches the expectation you have after the initial presentation of the problem. Given that this is from an academic setting, the solution is probably not usable in any practical sense--just a curiosity.
That said, you need more information, but here are some "answers" with varying levels of cheesy-ness:
1. ls is open source--go rewrite it to exclude directories by default
2. enforce a naming scheme for your directories (e.g. "all directories must start with an underscore"). In that case, you can use the "--hide" or "--ignore" options to filter the directories from the output
more serious approaches:
3. ls can take a list of files on the command-line. So you can have a command in this form: "ls <args1> `ls <args2>`" I experimented with the -p option (which adds a trailing slash '/' to directory entries) as part of args2 and then tried --hide="*/" as part of args1, but didn't get anywhere.
4. there may be an approach with globbing in the shell. I glanced through the man page, and saw reference to using "**" and "**/" as special globs/wildcards. I didn't look that hard or experiment at all.
a non-ls-exclusive solution:
The above assumes you can only use ls, but if you can use another tool, this should work easily: ls -l | grep -v "^d"
or the "reverse" of the same command: ls -l | grep "^-"
As a side note, there have been a number of "how do I display directories only" types of threads in the past. You might find some inspiration in them. But most of them will probably use the pipe-into-grep solution above.
Last edited by Dark_Helmet; 10-03-2010 at 08:10 PM.
ls -d */
ls -d **/ #for recursive listing. See the postscript below.
But I've tried dozens of ideas, and I'm starting to think files-only is impossible without the use of some outside tool. The best I've come up with so far is this.
Code:
ls -p | grep -v /$
Unfortunately, as Dark Helmet also discovered, ls itself seems to treat the -p backslashes independently of the --ignore or --hide options, so that's no good.
The only direction I can think to go, if there is a solution to this, is through globbing or some other path matching trickery. As a simple example, if you could be sure that files have extensions, while directories don't (a poor assumption of course), then this would work.
Code:
ls *.*
I still haven't figured out anything that will definitively exclude directories no matter what the name, however.
PS. ** is the new bash.v4 recursive listing option. It's disabled by default, so use shopt -s globstar to enable it. But I don't think it will likely have much use in this situation, unless the challenge is expanded to include recursiveness too.
I experimented with the -p option (which adds a trailing slash '/' to directory entries) as part of args2 and then tried --hide="*/" as part of args1, but didn't get anywhere
Here's an idea: maybe make something like sed or awk clip the directories out of the ls -p output. Now, I have next to zero knowledge of awk or regex syntax, so don't ask for a cut-'n-paste command or anything...just a thought.
One thing about that: you probably wouldn't be able to preserve any color-coding (e.g. if you used ls -p --color=auto, or if you have ls aliased to ls --color=auto as I do ).
One thing about that: you probably wouldn't be able to preserve any color-coding...
Sure you could. Just use --color=always and make sure your expression is designed to deal with the embedded non-printing characters on either side of the names. It'd probably be a bit of extra work, but far from impossible.
But then again this is just another variation of what's been pointed out before; that it's possible, indeed easy, when you can use an external tool to parse the output. There are likely dozens of good solutions you could come up with using various programs. I already have some ideas about how it could be done using various shell scripting techniques.
The challenge as I see it is whether there's any way to do it using only ls, and nothing else that could be considered a command (executable or shell built-in). In other words, things like globbing and needing to have certain shell options enabled first would be acceptable, but scripting mechanisms like loops and especially test probably wouldn't. I'm starting to believe there isn't any way to do it.
On the other hand there are other questions about the challenge that are even less clear. Long format, short format, any format? Current directory only, or recursive as well? It might help if we knew exactly what the expected output would be.
Yeah, IF it's possible, it will likely depend on both ls and the shell environment.
I played with things a little more because David's post got me thinking. I combined his any my approach.
Rather than describe with words, here's what I tried:
Code:
ls -1 --hide=`ls -d */`
In other words, I thought, "if getting a directory-only listing is a simple command, is there some way it could be turned into a filter?"
Unfortunately, the "PATTERN" as described in the man page for --hide won't accept and use the ls output like we want. For this approach to work, the interior directory listing would need it's output changed to use a vertical bar between the directory names. I saw no way of convincing ls to use those bars (which would need to be escaped mind you--otherwise the shell might see them as pipes--depending on the order of expansion/inerpretation).
Also, when thinking about that, I realized (again) how the shell handles things. The fileglobbing expansion happens before ls is executed.
That makes me believe the environment is really the key as opposed to ls. So, if the original question does indeed have a solution, it's more likely the result of the shell's fileglobbing, and we've assumed bash so far. I have little experience with tcsh, but that's a possibility. tcsh is more C-like in its syntax and hence, more "familiar" especially in a computer curriculum. There's also ksh, ash, and who knows how many others. Each handles fileglobbing differently.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.