I like using the cut command in Linux with the -c flag. However, I'm interested in finding a command that sort of does the set inverse of cut. Essentially, given the input:

drwxrwxrwx 2 root root 4096 4096 4 20:15 bin
drwxrwxrwx 2 root root 4096 4096 4 20:15 Desktop

I would like to see everything except “4096 4 20:15”. Here is the output:

drwxrwxrwx 2 root root bin
drwxrwxrwx 2 root root Desktop

I want to be able to literally cut out between characters x and y, if that makes sense.

Any ideas? I can't imagine it'd be a hard script to write but if there already exists a command for it, I'd love to use it.

  • 1
    That's also cut: cut -c -23,42-. But actually this is the worst possible idea. See Why you shouldn't parse the output of ls(1) for explanation. – manatwork Sep 8 '13 at 16:31
  • 3
    Is there stat on your system? (Usually is on Linux, its a GNU tool.) stat -c '%A %h %U %G %n' * – manatwork Sep 8 '13 at 16:35
  • 1
    The corresponding command to cut is paste, although I see that your question needs just another incantation of cut (as already answered). – Wildcard Nov 13 '16 at 9:51

As others have pointed out, you should not parse the output of ls. Assuming you are using ls only as an example and will be parsing something else, there are a few ways of doing what you want:

  1. cut with -d and -f

    cut -d ' ' -f 1,2,3,4,9

    from man cut:

    -d, --delimiter=DELIM
          use DELIM instead of TAB for field delimiter
    -f, --fields=LIST
          select only these fields;  also print any line
          that contains no delimiter  character,  unless
          the -s option is specified

    Specifically for ls this is likely to fail since ls will change the amount of whitespace between consecutive fields to make them align better. cut treats foo<space>bar and foo<space><space>bar differently.

  2. awk and its variants split each input line into fields on white space so you can tell it to print only the fields you want:

    awk '{print $1,$2,$3,$4,$9}'
  3. Perl

    perl -lane 'print "@F[0 .. 3,8]"'
  • @manatwork I edited my answer, is that what you meant? However, it does work quite often, I tested it in a simple directory and since the alignment was fine, cut worked as expected. – terdon Sep 8 '13 at 17:24
  • awk for $9 and perl for $F[8] will output only the first words of the file names. The later is easy to correct with print "@F[0 .. 3,8 .. $#F]". – manatwork Sep 9 '13 at 7:19
  • @manatwork please note that I am not using ls for any of my suggestions for exactly that reason. These will all break for weird file names, spaces and new lines and carriage returns oh my! – terdon Sep 9 '13 at 14:56
  • Yes, I observed the removal of ls but was not sure whether was only to shorten the examples or not. – manatwork Sep 9 '13 at 15:18
  • @manatwork no, it was to make it clear that I am not suggesting parsing ls. For all the reasons you pointed out. – terdon Sep 9 '13 at 15:19

You can get the inverse of the results of cut by using the --complement option. The cut man page says (somewhat unhelpfully):


          complement the set of selected bytes, characters or fields

So, for instance,

$ echo The fifth and sixth words will be missing | cut -d ' ' -f 5-6 --complement The fifth and sixth be missing


  • -d ' ' sets the delimiter to the space character
  • -f 5-6 selects the fields 5 through 6 ("words will") to be output
  • --complement returns the complement (inverse) of the selected text

Using stat to replace ls isn't a drop-in replacement, so for all the well-intentioned admonishment against parsing ls, I can appreciate the seduction...

Here's an almost equivalent of of an ls -a in the current dir:

find . -maxdepth 1 -print0|xargs -0 stat --format="%A %U %G %n"

Here's the nearest I could get it:

find . -maxdepth 1 -print0\
|awk 'BEGIN{RS="\0";FS="/";ORS="\0"}{if(/\//){print $2}else{print}}'\
|xargs -0 stat --format="%A %U %G %n"\
|LC_COLLATE=C sort -k4 

Now, to take an argument instead of just ., you'd want to put it into a function kinda like this:

function ls4up() {
    find . -maxdepth 1 -print0\
    |awk 'BEGIN{RS="\0";FS="/";ORS="\0"}{if(/^[^\/][^\/]*\//){print $2}else{print}}'\
    |xargs -0 stat --format="%A %U %G %n"\
    |LC_COLLATE=C sort -k4 

So now you see how easy it is to use stat instead of trying to parse the output of ls or something. /s

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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