11

Run Command ls on Current Directory and get the output:

$ ls
Applications Documents    Library      Music        Public
Desktop      Downloads    Movies       Pictures

I'd like to enumerate them like:

1. Applications
2. Desktop
3. Documents
4. Downloads
5. Library
6. Movies
7. Music
8. Pictures
9. Public

This could be achieved using less in an intermediate way

ls | less -N

How to enumerate them in a straightforward way?

  • Do you want this always to happen, or just sometimes? In the first case, you can create an alias of ls to one of the commands in the answers; in the second, create a new alias - say "lsn" to the command . – jamesqf Mar 26 '18 at 19:20
16

Or simply do:

ls -b |nl -s '. ' -w 1
1. a\ file\ with\ nonewline
2. a\ file\ with\nnewline
3. a\ file\ with\ space
4. afile

from man nl:

-s, --number-separator=STRING
              add STRING after (possible) line number
-w, --number-width=NUMBER
              use NUMBER columns for line numbers
13

You should pipe the output of ls to another command. My suggestion is to use awk in this way:

$ ls -b --group-directories-first | awk '{print NR ". " $0}'
1. dir1
2. dir2
3. dir3
4. z-dir1
5. z-dir2
6. z-dir3
7. file1
8. file2
9. file3
10. file4
11. file5
12. file6
13. file7
14. file\nnewline
  • Please note that the file file\nnewline contains newline character \n in its name that is escaped by the option -b.

  • the option --group-directories-first will output the directories before the files.

Another possible way is to use for loop (but in this case to place the directories in the begging of the list will become more difficult):

n=1; for i in *; do echo $((n++)). $i; done
11

if just showing a number is the case, then you have several options as following as well as your less -N way:

$ ls |cat -n
$ ls |nl

If you want customized output numbering, then I would suggest to use find and do whatever you want to print:

find . -exec bash -c 'for fnd; do printf "%d. %s\n" "$((++i))" "$fnd"; done ' _ {} +

POSIXly, you would do:

find . -exec sh -c 'for fnd; do i=$((i+1)); printf "%d.\t%s\n" "$i" "$fnd"; done ' _ {} +
  • In this case, i must be initialised beforehand: i=0; find ... – rexkogitans Mar 26 '18 at 15:07
  • that's not necessarily here, as the -exec sh -c '....' is running under separate sh shell. – αғsнιη Mar 27 '18 at 4:17
3

You can also do this entirely with a short Bash script:

#!/bin/bash
set -eu
shopt -s nullglob

[ "$#" -eq 0 ] || cd -- "$1"
i=0
for f in *; do
    printf '%d. %s\n' "$((++i))" "${f//$'\n'/^N}"
done |
cat -vt

You can even be fancy and pad the line number for more than 9 results:

#!/bin/bash
set -eu
shopt -s nullglob

[ "$#" -eq 0 ] || cd -- "$1"
ls=(*)
pad=${#ls[@]}
pad=${#pad}
i=0
for f in *; do
    printf '%*d. %s\n' "$pad" "$((++i))" "${f//$'\n'/^N}"
done |
cat -vt

Usage

Assuming that you saved the script as an executable file numbered-ls.sh in the current working directory:

./numbered-ls.sh [DIRECTORY]

The argument DIRECTORY is optional and defaults to the current working directory.

Explanation

  1. If the script was invoked with an argument change the working directory to the path in the first argument.

  2. Match all entries of the current working directory and look over them. For each entry increment a counter and print its value along with the name of the entry. Line break characters in the name of the entry are replaced with ^N.

  3. Pipe the output through cat -vt to deal gracefully with file names that contain non-printable characters that the terminal may interpret as control characters.

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.