Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

My goal is deceptively simple (at least to me). I wish to take the output of ls -l or ls -lh and select just one field.

I am looking for this to be as bulletproof as possible, by which I mean, assume that filenames can have a variable number of spaces, not everything in the field has the same length, etc.

Bonus points for having a script that will take the name of the the field (or even just a field number), and then return the contents of the field.

I want to turn

enter image description here

into:

enter image description here

share|improve this question
up vote 25 down vote accepted

Try ls -l | awk '{print $7}'.

awk selects columns so it's perfect for this task.

share|improve this answer
2  
As explained by @ormaaj: Do not rely on pieces of information being available in specific places with ls. The find command is tremendously helpful. – Paddy Landau Jul 18 '12 at 10:02

Never parse ls. Use GNU find. Or if portability isn't important, stat(1).

find . -maxdepth 1 -printf '%Td\n'

For reading data other than lists of filenames line-by-line and splitting into fields, see: BashFAQ/001

There are no methods to reliably read a newline-delimited list of filenames that make sense under most circumstances.

share|improve this answer

You may fetch the specific column in shell like:

ls -al | while read perm bsize user group size month day time file; do echo $day; done

or awk as shown in @Corey answer, cut -c44-45 would also work after adjustment (since ls has fixed columns) , or whatever else, however the main problem is that it won't be reliable and bulletproof (e.g. on Unix it may be $6, not $7, and it changes depending on arguments) making it not machine-friendly therefore it is not recommended to parse ls command at all.

The best is to use different available commands such as find or stat, which can provide relevant options to format the output as you need. For example:

$ stat -c "%x %n" *
2016-04-10 04:53:07.000000000 +0100 001.txt
2016-04-10 05:08:42.000000000 +0100 7c1c.txt

To return column of only days of modifications, try this example:

stat -c "%x" * | while read ymd; do date --date="$ymd" "+%d"; done

It's worth to note that GNU stat could have different options to BSD stat, so it still won't be bulletproof across different operating systems.

share|improve this answer
1  
+1 for mention that ls should not be parsed as well as for use of stat . date however is setup incorrectly. You should add --date=$ymd , since date by itself will print the current day, but the purpose here is to convert date format of the file – Serg Apr 10 at 4:37
    
The ls -la | cut -c32-33 command in total honesty is just completely unreliable, not only because of the possible pitfalls with the filenames, but simply because it depends on the usernames' length and on the files' size. The stat -c "%x" *.* command looks ok, but by using *.* you're restricing it only to filenames containing a dot. I guess the intention was to catch also hidden files; in that case you should enable globbing for dotfiles beforehand and use * instead of *.*: shopt -s dotglob; stat -c "%x" * | [...]. – kos Apr 10 at 4:50
    
Ah and what Serg said also, you should add --date="$ymd" to the date command, otherwise it will print the current day of the month. – kos Apr 10 at 5:01
    
Thanks for the comments. I've addressed the issues and provided a better initial example. – kenorb Apr 10 at 12:11

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.