12

Suppose my directory, Historic_Documents has the following files/sizes:

  • Declaration_of_Independence.txt 342 bytes
  • Magna_Carta.txt 1580 bytes
  • Treaty_of_Versaille.txt 752 bytes.

Is it possible using only the ls command to get following output?

342 Declaration_of_Independence.txt
1580 Magna_Carta.txt
752 Treaty_of_Versaille.txt
raul
  • 131
  • 1
  • 1
  • 5

7 Answers7

15

How to parse output from ls -l verbose listing with a while loop:
I looked at this question and thought OK this is something you can do fairly easily with find:

$ find -maxdepth 1 -type f -printf '%s %f\n'

Or

#!/bin/bash
for i in *; do
    stat --format '%s %N' "$i"
done

(%N will honor QUOTING_STYLE environment variable; default is 'shell-escape').

Only way to get size from ls is through verbose listing. By using read to read ls output; leading and trailing spaces will be removed from the word before assigned to a variable, the first word is assigned to the first variable and so on, when all variables are assigned, the remaining words will be added to the last variable, that way we can preserve spaces on the filename.

#!/bin/bash
while read -r p c u g s e n; do
    [[ $p = total ]] && continue || { echo -n "$s "; eval "ls -d $n"; }
done < <(ls -Lpl --time-style=+%s --quoting-style=shell-escape)

(using echo -n "$s "; eval "ls -d $n" is a bit excessive, but it shows how to use 'shell-escape' with other commands. If you just want to show the output for size and name, use echo "$s $n" instead)

read variables:

-rwxr-xr-x 1 bac0n bac0n 209 1572207800 script.sh
     ^     ^   ^     ^    ^      ^         ^
     p     c   u     g    s      e         n

ls options:

  • -L when showing file information for a symbolic link, show information for the file the link references rather than for the link itself.
  • -p append / indicator to directories.
  • -l use a long listing format.
  • --time-style time/date format with -l; its a good practice to set this to epoch in scripts.
  • --quoting-style quoting non-printable characters using the POSIX proposed ‘$''’ syntax.

test directory:

$ ls
a  'b'$'\r''c'   'd'$'\n''e'  "f'g"   h,i  'j k'  'l  m'  'n  '  '  o'
13

Using only the ls options, you can do this:

ls -sd --block-size=1 --format=single-column *

Here are the options:

  • -sd says to print the allocated file size in blocks and the d option removes the directory "total" line from the output

  • --block-size=1 prints 1 byte per size unit (instead of K)

  • --format=single-column says to print the results as a single column

  • * says to run ls on all files in the current directory and is needed when using the d option

This assumes your current directory is Historic_Documents.


EDIT:

Because you want the size of the file contents, I don't think you can do this with only ls options. However, you can use du to get the exact result you desire:

du -b *

The -b or --bytes option prints the actual file size in bytes which is also equivalent to the options: --apparent-size --block-size=1.

Apparent size is the size of the file (the similar to the sizes listed by ls -l) and not the allocated file size or disk usage.

mchid
  • 44,904
  • 8
  • 102
  • 162
5

With just ls, no, but with stat (if you have ls you have stat):

stat -c "%s %n" *
  • stat with a format (-c, --format) is the most flexible way to obtain file data
  • Although not explicitly stated in the man page, you can use width & precision specifiers on the fields, for instance to have the size listed on 8 columns:

    stat -c "%8s %n" *
    
xenoid
  • 5,759
3

Update 2

Here is a one-liner that uses awk, which has the benefit of also retaining multiple consecutive spaces in the filenames:

ls -l | awk 'BEGIN{FPAT="([[:space:]]*[^[:space:]]+)"; OFS = "";} FNR == 1 {next} {$1=$2=$3=$4=$6=$7=$8=""}1'
  • FPAT="([[:space:]]*[^[:space:]]+)" is used to set a regular expression of what a field should be. Here we set the field to have zero or more whitespace characters and at least one of every other character except whitespace. The suggestion about using FPAT was found in this Stack Overflow answer.

  • OFS = "" is used so that the output will only have a single space as a field separator (another one is added by the text manipulation).

  • FNR == 1 {next} is used so that a blank line at the beginning, that corresponds to the first line of the ls -l output that shows the total number of blocks used, won't be printed.

  • {$1=$2=$3=$4=$6=$7=$8=""}1 empties the specified fields and prints the rest, i.e. the fifth field (file size) and the ninth till the end (filename).

It should be noted that each line of the output of the above command will have one or more leading spaces. In my opinion this makes the output easier to read, however, you can remove the leading spaces by piping the awk command to sed as follows (remove the * from the sed command to remove just one leading space):

ls -l | awk 'BEGIN{FPAT="([[:space:]]*[^[:space:]]+)"; OFS = "";} FNR == 1 {next} {$1=$2=$3=$4=$6=$7=$8=""}1' | sed 's/^ *//'

Update

A better approach would be to use cut on the ls -l output:

ls -l | tr -s ' ' | cut -d ' ' -f 5,9-

Here, tr -s ' ' is used to squeeze multiple spaces between the fields of the ls -l output to one and then cut uses space as a delimiter to display the fifth field (file size) and all fields after the ninth (filename) of the ls -l output.

Note, however, that, if you have filenames with multiple consecutive spaces, they will be displayed as having single spaces, due to tr (thanks bac0n).


You can use this:

ls -sh
  • -s (or --size): prints the allocated size of each file, in blocks.
  • -h (or --human-readable) prints the size in a human readable format (i.e using K, M, etc. for thousands, millions, etc. respectively).

You can read the ls manpage for more info by running man ls in your terminal or by visiting the Ubuntu ls manpage online.

3

It's impossible to do with the ls command by itself. You can do it by piping ls -l output to other commands or with a totally different command like find as others have answered.

The tree command gives another alternative:

rick@alien:~/askubuntu$ tree -h
.
├── [8.8K]  aptfielout
├── [1.8K]  aptfilein
├── [ 435]  aptfileout
   (... SNIP ...)
├── [  38]  script
├── [4.0K]  subdir-A
│   ├── [  14]  1.mp4
│   ├── [  14]  2.mp4
│   ├── [  14]  3.mp4
│   └── [4.0K]  JSON
│       └── [4.0K]  JSON
│           ├── [   7]  1.json
│           ├── [   7]  2.json
│           ├── [   7]  3.json
│           └── [   7]  4.json
   (... SNIP ...)
├── [1.5K]  ttlus
└── [1.3K]  ttlus~

7 directories, 57 files

The tree option passed is -h for human readable size. For size in exact bytes pass -s.

2
ls --size --format=single-column
abc
  • 116
1

Command:

ls -l | awk '{print $5, $9}'