27

I am ignorant as to whether ls is capable of displaying a filetype column.

Doing a quick online search and searching the man did not reveal such a capability. Is it capable of doing this?

Clarification: This is especially helpful if files do not have an extension.

Update

As of 2018-04-28 the answers have been quite interesting however they did not provide what I was looking for. More specifically,

  • file does give the actual filetypes but it doesn't integrate well with ls. Specifically, I use ls -lhtrpG --group-directories-first --color=always

  • ls -F is an ls solution however it provides symbols not a column of actual filetypes.

For this reason I have not marked any of the answers as the answer I am looking for.

2

5 Answers 5

33

I think the best way to display a file type is using this command:

file <filename>

If you want to list the types of all files in a directory, just use:

file *

<code>file *</code> sample from my computer

For more details about the arguments, see:

man file
5
  • 1
    While this answer doesnt directly respond to the OP's question, it shows the correct way of finding the mime type of a file and should be marked as the correct answer. To get the mime type only, use: file --mime-type filename. Apr 26, 2018 at 23:56
  • @PedroLobito I think the closely related question covers file quite well, but this question is different.
    – dessert
    Apr 27, 2018 at 8:06
  • I vote this answer up given that you were the first to give a file answer. As I replied to the others this doesn't suffice (it needs to be integrated with ls) so I keep it at a vote up. Thank you.
    – user10853
    Apr 29, 2018 at 21:57
  • 1
    file * is the best answer
    – nanquim
    Jan 13, 2020 at 0:09
  • 1
    file --mime /dev/* for list mimes in directory /dev instead of current Mar 7, 2020 at 4:41
19

file is definitely the right choice to get the file type information you want. To combine its output with that of ls I suggest to use find:

find -maxdepth 1 -type f -ls -exec file -b {} \;

This finds every file in the current directory and prints the output of ls -dils as well as the output of file -b for it, each on an own line. Example output:

  2757145      4 -rw-rw-r--   1 dessert dessert      914 Apr 26 14:02 ./some.html
HTML document, ASCII text
  2757135      4 -rw-rw-r--   1 dessert dessert      201 Apr 13 15:26 ./a_text_file
UTF-8 Unicode text, with CRLF, LF line terminators

But, as you don't want a filetype line but rather a filetype column, here's a way to get rid of the newline character between the lines:

find -maxdepth 1 -type f -exec sh -c "ls -l {} | tr '\n' '\t'; file -b {}" \;

Sample output:

-rw-rw-r-- 1 dessert dessert 914 Apr 26 14:02 ./some.html    HTML document, ASCII text
-rw-rw-r-- 1 dessert dessert 201 Apr 13 15:26 ./a_text_file  UTF-8 Unicode text, with CRLF, LF line terminators

That new column is quite long, so let's cut everything from the first comma:

find -maxdepth 1 -type f -exec sh -c "ls -l {} | tr '\n' '\t'; file -b {} | cut -d, -f1" \;

The output of that looks like this:

-rw-rw-r-- 1 dessert dessert 914 Apr 26 14:02 ./some.html    HTML document
-rw-rw-r-- 1 dessert dessert 201 Apr 13 15:26 ./a_text_file  UTF-8 Unicode text

This is not quite handy, so how about an alias? With the following line in your ~/.bash_aliases file you just need to run lsf to get the above output for the current directory.

alias lsf='find -maxdepth 1 -type f -exec sh -c "ls -l {} | tr '"'\n'"' '"'\t'"'; file -b {} | cut -d, -f1" \;'
7
  • 1
    If you use a function instead of an alias, that will be less of a quoting hell, and if you use paste or column, you could get better alignment: lsf () { find -maxdepth 1 -type f -exec bash -c 'column <(ls -l "$@") <(file -b "$@" | cut -d, -f1)' _ {} + ; } The alignment issue is not evident in the answer because of the similar sizes and dates. (This will also be slightly faster, since the commands will be invoked fewer times instead of once per file.)
    – muru
    Apr 27, 2018 at 10:11
  • @muru Thanks for the many good suggestions! Does this column aproach work for you? It just prints the output of ls -l for every file followed by file's output for every file for me, as if the shell would just do ls -l "$@"; file -b "$@" | cut -d, -f1
    – dessert
    Apr 27, 2018 at 11:38
  • It does. paste.ubuntu.com/p/KjPthXPDPb - the top part is from the alias and the bottom part is the function, both run from /etc.
    – muru
    Apr 27, 2018 at 12:46
  • I think I see the problem - if column's output is not to the terminal, you need to specify the column count or it will output the files one after the other; so column -c "$COLUMNS" ... should work in either case.
    – muru
    Apr 27, 2018 at 12:48
  • You are launching (at least?) 5 processes for each file, so this is probably going to be slow when there are lots of files in a directory…
    – JanC
    Apr 27, 2018 at 19:28
11

For clarity, I'm going to point out that you can see the file type in a basic sense with ls, using the -F flag (classify) which appends a symbol to the filename depending on its type:

‘-F’
‘--classify’
‘--indicator-style=classify’
     Append a character to each file name indicating the file type.
     Also, for regular files that are executable, append ‘*’.  The file
     type indicators are ‘/’ for directories, ‘@’ for symbolic links,
     ‘|’ for FIFOs, ‘=’ for sockets, ‘>’ for doors, and nothing for
     regular files.

You can see that information slightly less cryptically displayed in the first letter of the output of ls -l, though. wjandrea's answer describes this in more detail.

But I don't think this is what you mean by file type. The ls command does not look inside regular files - only at directory listings (which store filenames) and inodes (which store metadata, including the "type" in the sense mentioned earlier).

So, the ls command cannot show the file type in the sense of whether it is a JPG image or a binary file or a text file or a LibreOffice document of some kind, because it does not have that information.

For that, as singrium's answer points out, you need the file command, which looks at the first 50-100kB or so of files' contents to determine their type.

0
10

One form of filetype is whether a file is a regular file, directory, device, symlink, etc. ls can show this using options -l or -F.

  • Option -l will show the filetype as a single character at the start of a listing, e.g:

    $ ls -l
    drwxrwxr-x 2 user user 4096 Dec 11 00:18 DIR
    -rw-rw-r-- 1 user user    0 Dec 11 00:18 FILE
    lrwxrwxrwx 1 user user    4 Dec 11 00:19 LINK -> FILE
    

    Where - is a regular file, d is a directory, and l is a symlink.

  • Option -F will show the filetype as a suffix, e.g:

    $ ls -F
    DIR/ FILE LINK@
    

    Where no suffix is a regular file, / is a directory, and @ is a symlink.

More info on these is available in info coreutils 'ls invocation', summed up here:

For -l:

‘-’ regular file
‘b’ block special file
‘c’ character special file
‘C’ high performance (“contiguous data”) file
‘d’ directory
‘D’ door (Solaris 2.5 and up)
‘l’ symbolic link
‘M’ off-line (“migrated”) file (Cray DMF)
‘n’ network special file (HP-UX)
‘p’ FIFO (named pipe)
‘P’ port (Solaris 10 and up)
‘s’ socket
‘?’ some other file type

For -F:

nothing for regular files
‘*’ regular files that are executable
‘/’ directories
‘@’ symbolic links
‘|’ FIFOs
‘=’ sockets
‘>’ doors
0
0

here is another way using paste to merge two output of ls and file command

paste <(ls -dl *) <(file * | cut -d: -f2)

You must log in to answer this question.

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