简体   繁体   中英

How to list all subdirectories and files using nodeJS?


Using node ssh2-sftp-client , I'd like to recursively list all directories (and in a second time, files) of a SSH-remote directory root.

I'm using nodejs

node v12.15.0

I've found a usefulness same but non answered StackOverflow question .

Documentation "basic usage" (see ssh2-sftp-client ) gives a standard use of sftp connection and list of directory '/tmp':

const Client = require('ssh2-sftp-client');
const sshConfig = {
    host: process.env.REMOTE_SSH_HOST,
    port: 22,
    username: process.env.REMOTE_SSH_USERNAME,
    password: process.env.REMOTE_SSH_PASSWORD,
    readyTimeout: 99999,
};
let sftp = new Client();
sftp.connect(sshConfig).then(() => {
    return sftp.list('/tmp');
}).then(data => {
    console.log(data, 'the data info');
}).catch(err => {
    console.log(err, 'catch error');
});

I've tried to add a function recursively reading every sub-directories, but I got an error on forEach sentence saying:

sftp.list(...).forEach is not a function

although sftp.list() returns an array.
I know there is something with sftp.list method that return a Promise and then an array, but cannot figure out what and where I should modify.

Here is my code:
sshList.js

const Client = require('ssh2-sftp-client');
const sshConfig = {
    host: process.env.REMOTE_SSH_HOST,
    port: 22,
    username: process.env.REMOTE_SSH_USERNAME,
    password: process.env.REMOTE_SSH_PASSWORD,
    readyTimeout: 99999,
};
let sftp = new Client();

// Function to read sub-directories
async function SubRead(sub, parentDirectory) {
    if (sub['type'] === 'd') {
        await Read(parentDirectory + '/' + sub['name']);
    }
}
async function Read(directory) {
    console.log('Read(' + directory + ')');
    const result = sftp.list(directory);
    result.forEach( x => SubRead(x, directory) );
}
async function main(directory) {
    try {
        console.log('Connecting...');
        await sftp.connect(sshConfig).then(async () => {
            console.log('Connected');
            await Read(directory);
        });
    } catch (e) {
        console.error(e.message);
    } finally {
        console.log('Closing session...');
        await sftp.end();
        console.log('Session closed.');
    }
}
console.log('Application started');
main('/home/user/path').then(r => {
    console.log('Application ended.');
});

Launch with

node sshList.js

Adding sample structure

Let say remote directory "/home/user/path" to read has this tree structure:

.
├── Level1_A
│   ├── Level2_AA
│   │   ├── Level3_AAA
│   │   ├── toto
│   │   ├── toto.txt
│   │   ├── txttoto
│   │   └── txt.toto
│   ├── Level2_AB
│   └── Level2_AC
├── Level1_B
│   ├── Level2_BA
│   ├── Level2_BB
│   └── Level2_BC
└── Level1_C
    ├── Level2_CA
    └── Level2_CB

Running node command (see upper) gives an incomplete result:

Application started
Connecting...
Connected
Reading(/home/iliad/alain)
Reading(/home/iliad/alain/Level1_B)
Reading(/home/iliad/alain/Level1_A)
Reading(/home/iliad/alain/Level1_C)
Closing session...
Session closed.
Application ended.

No way to find "Level 2" directories !
I was expecting (do not consider "# Missing" text):

Application started
Connecting...
Connected
Reading(/home/iliad/alain)
Reading(/home/iliad/alain/Level1_B)
Reading(/home/iliad/alain/Level1_B/Level2_BA) # Missing
Reading(/home/iliad/alain/Level1_B/Level2_BB) # Missing
Reading(/home/iliad/alain/Level1_B/Level2_BC) # Missing
Reading(/home/iliad/alain/Level1_A)
Reading(/home/iliad/alain/Level1_A/Level2_AA) # Missing
Reading(/home/iliad/alain/Level1_A/Level2_AA/Level4_AAA) # Missing
Reading(/home/iliad/alain/Level1_A/Level2_AB) # Missing
Reading(/home/iliad/alain/Level1_A/Level2_AC) # Missing
Reading(/home/iliad/alain/Level1_C)
Reading(/home/iliad/alain/Level1_C/Level2_CA)
Reading(/home/iliad/alain/Level1_C/Level2_CB)
Closing session...
Session closed.
Application ended.

What am I missing?
Any help will be welcome !

sftp.list returns a promise so you need to await it before using it. Something like this should work

const Client = require('ssh2-sftp-client');
const sshConfig = {
    host: process.env.REMOTE_SSH_HOST,
    port: 22,
    username: process.env.REMOTE_SSH_USERNAME,
    password: process.env.REMOTE_SSH_PASSWORD,
    readyTimeout: 99999,
};
let sftp = new Client();

async function Read(directory) {
    console.log('Read(' + directory + ')');
    const result = await sftp.list(directory);
    for(const sub of result) {
      if (sub['type'] === 'd') {
          await Read(directory + '/ ' + sub['name']);
      }
    }
}

async function main(directory) {
    try {
        console.log('Connecting...');
        await sftp.connect(sshConfig).then(() => {
            console.log('Connected');
            await Read(directory);
        });
    } catch (e) {
        console.error(e.message);
    } finally {
        console.log('Closing session...');
        await sftp.end();
        console.log('Session closed.');
    }
}
console.log('Application started');
main('/home/user/path').then(r => {
    console.log('Application ended.');
});

sftp.list(directory).forEach(

have to be either:

 sftp.list(directory).then((myList)=> {myList.foreach()})//with your code
                     .catch((err)=> console.log(err))//never forget to catch

or declare you function async and

try{
const myList = await sftp.list(directory);
}catch(err){console.log(err)}//NEVER forget to catch

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM