1

I'm trying to learn bash and I'm trying to list the files I have in a folder using a bash script from a.sh, like this:

1: a.sh
2: b.sh
3: c.sh

I've looked at ls and find commands, but they don't seem to prefix numerically like I want. Please Help!

  • ls -q | grep -n ^ should work with all kind of filenames if you don't mind seeing question marks instead of funky chars. By the way, is this homework ? – don_crissti Feb 25 '16 at 18:50
4

There are many ways of doing this. For example, if you are sure your file names don't contain newlines, you can do:

$ ls | cat -n
     1  a.sh
     2  b.sh
     3  c.sh
     4  d.sh

A safer way that can deal with file names containing newlines or any other strange characters:

$ c=0; for file in *; do ((c++)); printf '%s : %s\n' "$c" "$file"; done
1 : a.sh
2 : b.sh
3 : c.sh
4 : d.sh

To see why the latter two are better, create a file name that contains newlines:

$ touch 'a long file name'
$ touch 'another long filename, this one has'$'\n''a newline character!'

Now, compare the output of the two approaches:

$ ls | cat -n
     1  a long file name
     2  another long filename, this one has
     3  a newline character!
     4  a.sh
     5  b.sh
     6  c.sh
     7  d.sh

As you can see above, parsing ls (which is generally a bad idea) results in the file name with the newline being treated as two separate files. The correct output is:

$ c=0; for file in *; do ((c++)); printf '%s : %s\n' "$c" "$file"; done
1 : a long file name
2 : another long filename, this one has
a newline character!
3 : a.sh
4 : b.sh
5 : c.sh
6 : d.sh

As @Vikyboss points out in the comments, the shell solution above will set the variable $c which will persist after the loop exits. To avoid that, you could add unset c at the end, or use yet another approach. For example:

$ perl -le 'for(0..$#ARGV){print $_+1 ." : $ARGV[$_]"}' *
1 : a long file name
2 : another long filename, this one has
a newline character!
3 : a.sh
4 : b.sh
5 : c.sh
6 : d.sh
  • Note: Your second solution adds(pollutes?) variable c to the current shell of execution. – Vikyboss Feb 25 '16 at 18:53
  • @Vikyboss true. You can always unset c at the end if that's a problem. Still, I added a perl solution that doesn't have this issue. – terdon Feb 25 '16 at 18:57
  • You could always do: f(){ local i; for ((i=1; i<=$#;i++)); do printf '%03d: %s\n' "$i" "${!i}"; done; }; f * and if even the function is considered pollution: unset -f . However, no variable or function will remain when the code is executed from a script. So, I do not see pollution as anything important. – user79743 Feb 25 '16 at 20:30
1

This will do?

ls | awk '{print NR": "$0}'
1: andy
2: a.out
3: exclude

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.