6

I'd like to loop over the files in a directory using Vimscript. Reading usr_41.txt and having searched around, the best I can come up with is something like let dir_contents = system('ls')

But since system() isn't returning a list, I can't loop over it. Is there either a way I can save the results of a system call as a list, or a Vim command or function that does so already?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Thomas
  • 5,736
  • 8
  • 44
  • 67

5 Answers5

5

You can get a list with split(system('ls'), '\n'), which will give you a list of files providing you don't have files with newlines in them.

richq
  • 55,548
  • 20
  • 150
  • 144
2

I just discovered that there is a subtlety to these answers:

Currently (Jan 2018), vim has systemlist() that will answer your needs quite well:

let l:ls=systemlist("ls")
" or let dir_contents=etc etc

However, if you are doing something besides "ls" you might run into a weird bit of tricky behavior: trailing blank lines will get dropped (as of Jan 2018). If this is not a problem, don't worry, use systemlist() and be happy. If it is a problem, you probably want to do something like this:

let l:myvar=system("myprogram -that -returns -blank -lines")
l:mylist=split(l:myvar, "\n", 1) " the 1 is to keep empty lines

Hope that helps someone!

Peter Kay
  • 133
  • 7
1

Try something like

split(system('ls', nr2char(10))

I am currently not on a Unix system, so I can't try it myself, but it works on Windows (and dir), such as

for FILE in split(system('dir /b', nr2char(10))
  echo 'File is: ' . FILE
endfor
René Nyffenegger
  • 39,402
  • 33
  • 158
  • 293
1

There is a built-in glob() function. To get a list of files in current directory on windows you could use split(glob('.\\*'), "\n"). On *nix it is much more complicated as

  1. POSIX allows everything except NULL to be in filename. Everything here means that newline ("\n") is also allowed.
  2. glob() function does not return filenames starting with dot unless explicitely requested (using glob('dir/.*')).
  3. When explicitely requested to list filenames starting with dot glob() also shows . (current directory) and .. (parent directory) special directories.

In order to solve this problems you have to use something like this (or use vim with python support and python's own os.listdir function).

If you don't mind having frawor in dependencies, you could do the following:

execute frawor#Setup('0.0', {'@/os': '0.0'})
<...>
let dir_contents=s:_r.os.listdir('.')

About getting list of lines from a shell command: if you know that command you launch won't output NULLs, you can use split(system(cmd), "\n", 1) (maybe without last argument if you don't care about empty lines). If you know that command may output NULLs and you want to keep them, you have to do more work:

noautocmd new
read !cmd
let s:shell_output=getline(2, line('$'))
noautocmd bwipeout!

Note that NULLs in this case will get replaced with newlines inside a s:shell_output list, while actual newlines will be represented as string ends.

ZyX
  • 52,536
  • 7
  • 114
  • 135
0

systemlist added in Vim 7.4:248 does exactly what you want:

:echo systemlist('printf "a\nb\n"')

output:

['a', 'b']

From the docs http://vimhelp.appspot.com/eval.txt.html#eval.txt

systemlist({expr} [, {input}])                          systemlist()
                Same as system(), but returns a List with lines (parts of 
                output separated by NL) with NULs transformed into NLs. Output 
                is the same as readfile() will output with {binary} argument 
                set to "b".

                Returns an empty string on error.
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985