1

I have a directory with subdirectories and files structured like this:

01/fileA
01/fileB
01/fileC
02/fileD
02/fileE
03/fileF
03/fileG
03/fileH
04/fileI

I'd like to get a CSV that looks like this:

01, fileA, fileB, fileC
02, fileD, fileE
03, fileF, fileG, fileH
04, fileI

In other words, I want to generate a CSV with one row per subdirectory, with files listed as columns.

Is it possible to do this from the Linux command line?

3
  • When you say Bash, you mean bash and only bash? No sed, awk, find or other standard utils? Nov 17 '16 at 21:59
  • Any standard utils are okay, just edited question to clarify.
    – Nathan
    Nov 17 '16 at 22:02
  • FYI, standard CSVs should not have a space and a comma as a delimiter—just a comma. It's less human readable, but more computer friendly.
    – Wildcard
    Nov 18 '16 at 1:53
2

That can be done in a number of ways. One simple method could be this

for d in *
do  echo -n "$d, "
    ls -m $d
done
5
  • Thank you, this helps a lot. But, I'm getting a line feed before the last file sometimes. 01, fileA, fileB, fileC [LF] 02, fileD [LF] fileE [LF] 03, FileF [LF] and so on. There are no commas in file name either.
    – Nathan
    Nov 17 '16 at 22:40
  • That sounds strange. It looks as if the ls for directory 02 was run without -m. Do you have an actual example? A file tree that causes this? Nov 17 '16 at 23:02
  • 1
    Use ls -w0 -m "$d" to avoid hitting the default line length too early
    – roaima
    Nov 17 '16 at 23:20
  • Ah, good point! Nov 18 '16 at 18:56
  • In my version OS ls -w0 caused an error, but I was able to use ls -w99999999. Thanks!
    – Nathan
    Nov 18 '16 at 22:00
1

It's probably overkill, but using GNU datamash

find 0? -type f | sort -t/ | datamash -t\/ groupby 1 collapse 2 | sed 's/\//,/'
01,fileA,fileB,fileC
02,fileD,fileE
03,fileF,fileG,fileH
04,fileI

Or with a perl hash of arrays

find 0? -type f | perl -F/ -alne '
  push @{$dirs{$F[0]}}, $F[1]; 
  END{
    for $d (sort keys %dirs) {print join ",", $d, sort @{$dirs{$d}}}
  }'
01,fileA,fileB,fileC
02,fileD,fileE
03,fileF,fileG,fileH
04,fileI

or with GNU awk

find 0? -type f | sort -t/ | gawk -F/ '
  {dirs[$1] = dirs[$1] "," $2} 
  END {
    n = asorti(dirs,sdirs); 
    for(i=1;i<=n;i++) print sdirs[i] "" dirs[sdirs[i]]
}'
01,fileA,fileB,fileC
02,fileD,fileE
03,fileF,fileG,fileH
04,fileI

With GNU awk > 4.0 you can simplify the array traversal to

  END {
    PROCINFO["sorted_in"] = "@ind_num_asc";
    for (d in dirs) print d "" dirs[d];
  }'
0

Here is another solution

find * -type d -printf "\n%p, " -exec ls -w0 -m {} \; |
    sed -e '/^$/d' -e 's/, *$//'

Output

01, fileA, fileB, fileC
02, fileD, fileE
03, fileF, fileG, fileH
04, fileI

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.