This is a read-only snapshot of the ComputerCraft forums,
taken in April 2020.
Search engine across multiple disk drives?
Started by Kangaroo2K1, 27 April 2015 - 03:36 AMPosted 27 April 2015 - 05:36 AM
Hey, I'm fairly new to CC. I'd like to make a program where you enter a keyword into the program (running, not editing) and it searches across multiple disk drives in your wired network, and shows the results. Basically I want to make a search engine for my multi-drive network. I don't really know what to do, so all help is appreciated. Thanks! :)/>
Posted 27 April 2015 - 06:40 AM
You'll first want to become familiar with looping, and with tables.
The way I'd approach this would be to first take the result of fs.list("") (which returns a numerically indexed table containing the names of all the files and folders in the root of the drive), then start a loop that inspects every element in that table, removing them as it goes. When it encounters a folder, it'd fs.list() its contents and add the contents of the new table to the first. When it encounters a match for the search term, it'd add that to a third table, which is what it'd return when the first table finally emptied.
The way I'd approach this would be to first take the result of fs.list("") (which returns a numerically indexed table containing the names of all the files and folders in the root of the drive), then start a loop that inspects every element in that table, removing them as it goes. When it encounters a folder, it'd fs.list() its contents and add the contents of the new table to the first. When it encounters a match for the search term, it'd add that to a third table, which is what it'd return when the first table finally emptied.
Posted 27 April 2015 - 11:38 PM
Thanks for the reply. I've been trying to code this for about 4 hours now, but still getting stumped overall. Could you (or anyone else) write this so that when you run it from the computer's directory (computer's HDD) it shows the results for all drives on the network and the computer? Thanks so much!You'll first want to become familiar with looping, and with tables. The way I'd approach this would be to first take the result of fs.list("") (which returns a numerically indexed table containing the names of all the files and folders in the root of the drive), then start a loop that inspects every element in that table, removing them as it goes. When it encounters a folder, it'd fs.list() its contents and add the contents of the new table to the first. When it encounters a match for the search term, it'd add that to a third table, which is what it'd return when the first table finally emptied.
Edited on 27 April 2015 - 11:30 PM
Posted 28 April 2015 - 01:33 AM
We don't generally write code on request. Post what you've got so far and explain what you're stuck on and we can help.
Posted 28 April 2015 - 03:30 AM
Alright, I am very bad at coding (really sorry) but here's what I got: print(fs.list"") but all I get is a value (do I not print it?), nothing shown as a result. Any way to make it show all files, and then what would I enter to have it allow me to enter a search box to refine all files, and then what would I enter to actually single out results AND for it to show me what disk its on? Again, really sorry I'm bad at this. Thanks though for the help!
Posted 28 April 2015 - 07:22 AM
well, it works like this:
for i,v in pairs(fs.list(path)) do
print(v)
end
Posted 28 April 2015 - 11:37 AM
well, it works like this:for i,v in pairs(fs.list(path)) do print(v) end
That only prints the files and folders in the root folder of the current computer, not the disk drives nor the contents of folders.
Posted 28 April 2015 - 12:42 PM
Alright, how would I code it to see over all drives from being run in the computer? And what would I do next? Thanks.well, it works like this:for i,v in pairs(fs.list(path)) do print(v) end
That only prints the files and folders in the root folder of the current computer, not the disk drives nor the contents of folders.
Posted 28 April 2015 - 12:52 PM
Alright, how would I code it to see over all drives from being run in the computer? And what would I do next? Thanks.
Did you just want the names of the files or the paths too?
I have a script I use in my xPlore file manager (It will take some time to search through lots of items)
Edited on 28 April 2015 - 10:52 AM
Posted 28 April 2015 - 12:58 PM
Use this:
Try this, and it should generate a file for ALL the files in all disk drives…
Depending on speeds my emulator runs at 1000fps and searches the files at about 40 per second, even when taking out sleep otherwise it may error…
function searchall()
local function yieldFsList(startPath)
local list = fs.list(startPath)
for _, file in ipairs(list) do
local path = fs.combine(startPath, file)
if fs.isDir(path) then
yieldFsList(path)
else
coroutine.yield(path, file)
end
end
end
return coroutine.wrap(function() yieldFsList(start or "/") end
end
results = {}
for path, name in searchall() do
table.insert(results[1], name)
table.insert(results[2], path)
sleep(0)
end
local output = fs.open("searchresults", "w")
output.write(textutils.serialize(results))
output.close()
Try this, and it should generate a file for ALL the files in all disk drives…
Depending on speeds my emulator runs at 1000fps and searches the files at about 40 per second, even when taking out sleep otherwise it may error…
Edited on 28 April 2015 - 10:59 AM
Posted 28 April 2015 - 01:21 PM
yes, this is what it should be. I was just correcting the fs.list trouble he had ;)/>
Posted 28 April 2015 - 09:31 PM
I put your code into the file I was trying to work with, saved it (entered code using Notepad, so there was no other formatting) and loaded into my game. After returning to my network pc I attempted to run the program, but it said in line 13 you were missing an end parenthesis. I checked to see, but it seemed to look correct. Frustrated, I deleted that file using the computer, and retyped your entire code. After another attempt, is said it was expecting <name> after search (program name I used). I had tried various combinations but it didn't seem to work. EX: search <mydoc1>, search<mydoc1>, search mydoc1, etc… What am I doing wrong here? Thanks for the awesome code, help is appreciated!Use this:function searchall() local function yieldFsList(startPath) local list = fs.list(startPath) for _, file in ipairs(list) do local path = fs.combine(startPath, file) if fs.isDir(path) then yieldFsList(path) else coroutine.yield(path, file) end end end return coroutine.wrap(function() yieldFsList(start or "/") end end results = {} for path, name in searchall() do table.insert(results[1], name) table.insert(results[2], path) sleep(0) end local output = fs.open("searchresults", "w") output.write(textutils.serialize(results)) output.close()
Try this, and it should generate a file for ALL the files in all disk drives…
Depending on speeds my emulator runs at 1000fps and searches the files at about 40 per second, even when taking out sleep otherwise it may error…
Posted 28 April 2015 - 09:49 PM
You need to edit a couple things. i'll fix that code for you.
local tArgs = {...} --# Need to grab your extra word
function searchall(start) --#Need to have it passed here so that you can choose
local function yieldFsList(startPath)
local list = fs.list(startPath)
for _, file in ipairs(list) do
local path = fs.combine(startPath, file)
if fs.isDir(path) then
yieldFsList(path)
else
coroutine.yield(path, file)
end
end
end
return coroutine.wrap(function() yieldFsList(start or "/") end) --# Someone forgot a ) here.
end
results = {}
for path, name in searchall(tArgs[1]) do --#Sending over your path
table.insert(results[1], name)
table.insert(results[2], path)
sleep(0)
end
local output = fs.open("searchresults", "w")
output.write(textutils.serialize(results))
output.close()
That's about all I see being wrongPosted 28 April 2015 - 10:54 PM
Doesn't seem to work, say's table excepted, got nil even though the file is in one of the drives within my network. If someone does fix this, could they also post the command so I know I'm doing this right? Thanks again! :)/>You need to edit a couple things. i'll fix that code for you.That's about all I see being wronglocal tArgs = {...} --# Need to grab your extra word function searchall(start) --#Need to have it passed here so that you can choose local function yieldFsList(startPath) local list = fs.list(startPath) for _, file in ipairs(list) do local path = fs.combine(startPath, file) if fs.isDir(path) then yieldFsList(path) else coroutine.yield(path, file) end end end return coroutine.wrap(function() yieldFsList(start or "/") end) --# Someone forgot a ) here. end results = {} for path, name in searchall(tArgs[1]) do --#Sending over your path table.insert(results[1], name) table.insert(results[2], path) sleep(0) end local output = fs.open("searchresults", "w") output.write(textutils.serialize(results)) output.close()
Edited on 28 April 2015 - 08:54 PM
Posted 29 April 2015 - 02:24 PM
The code is trying to insert the name variable to the key value 1 of {results}, which doesn't exist because the table results is {}
Remove the "[1]" and "[2]" and itshould works.
But you could do this:
Remove the "[1]" and "[2]" and it
But you could do this:
table.insert(results, 1, name)
table.insert(results, 2, name)
Edited on 29 April 2015 - 12:26 PM
Posted 29 April 2015 - 02:55 PM
The code is trying to insert the name variable to the key value 1 of {results}, which doesn't exist because the table results is {}
Remove the "[1]" and "[2]" and itshouldworks.
But you could do this:table.insert(results, 1, name) table.insert(results, 2, name)
Yeah he is using the file manager I made which contains the search function as I took it from that.
Posted 30 April 2015 - 12:48 AM
Square is correct, the indexes at 1 and 2 are not initialized to tables.
There we go, I fixed it again
local tArgs = {...} --# Need to grab your extra word
function searchall(start) --#Need to have it passed here so that you can choose
local function yieldFsList(startPath)
local list = fs.list(startPath)
for _, file in ipairs(list) do
local path = fs.combine(startPath, file)
if fs.isDir(path) then
yieldFsList(path)
else
coroutine.yield(path, file)
end
end
end
return coroutine.wrap(function() yieldFsList(start or "/") end) --# Someone forgot a ) here.
end
local results = {}
results[1] = {}
results[2] = {}
for path, name in searchall(tArgs[1]) do --#Sending over your path
table.insert(results[1], name)
table.insert(results[2], path)
sleep(0)
end
local output = fs.open("searchresults", "w")
output.write(textutils.serialize(results))
output.close()
There we go, I fixed it again
Posted 30 April 2015 - 09:27 PM
Even though I have a solution to this problem, I'd still like to have this code. This time during the first run the computer hung. After rebooting I did the command and then a keyword, it then said that my keyword was not a directory. How am I supposed to search across multiple drives if I don't know what directory I need to find it in?Square is correct, the indexes at 1 and 2 are not initialized to tables.local tArgs = {...} --# Need to grab your extra word function searchall(start) --#Need to have it passed here so that you can choose local function yieldFsList(startPath) local list = fs.list(startPath) for _, file in ipairs(list) do local path = fs.combine(startPath, file) if fs.isDir(path) then yieldFsList(path) else coroutine.yield(path, file) end end end return coroutine.wrap(function() yieldFsList(start or "/") end) --# Someone forgot a ) here. end local results = {} results[1] = {} results[2] = {} for path, name in searchall(tArgs[1]) do --#Sending over your path table.insert(results[1], name) table.insert(results[2], path) sleep(0) end local output = fs.open("searchresults", "w") output.write(textutils.serialize(results)) output.close()
There we go, I fixed it again
Posted 01 May 2015 - 01:37 AM
Another oversight, since the code will have to run over multiple drives, they'll each have a directory unique to them. However it also occurs to me that you're just looking for a specific file. Let me rewrite that code in it's entirety so that you can look for a specific file, without needing to know it's directory.Even though I have a solution to this problem, I'd still like to have this code. This time during the first run the computer hung. After rebooting I did the command and then a keyword, it then said that my keyword was not a directory. How am I supposed to search across multiple drives if I don't know what directory I need to find it in?
I'll edit this post when I finish it. Shouldn't be long.
local tArgs = {...}
local modem = peripheral.wrap("right")
local function findFile(fileName)
local function recurFile(directory,searchTerm)
for a,v in pairs(directory) do
if fs.isDir(v) then
local fnd = recurFile(fs.combine(directory,v),searchTerm)
if fnd ~= nil then
return fnd
end
elseif v == searchTerm then
return {true,fs.combine(directory,v)}
end
end
end
for a,v in pairs(modem.getNamesRemote()) do
if peripheral.getType(v) == "drive" then
local found = recurFile(disk.getMountPath(v),fileName)
if found ~= nil then
return unpack(found)
end
end
end
end
local found,path = findFile(tArgs[1])
if found then print(path) end
Make sure you edit that modem part to whatever side your wired modem is onEdited on 30 April 2015 - 11:48 PM
Posted 01 May 2015 - 02:16 AM
Ended up with bad argument: table expected, got string. Doesn't seem to like how I ended up doing the command (search alongtime ago; one of the files across my network). And I did wrap the correct wired modem to the correct side.Another oversight, since the code will have to run over multiple drives, they'll each have a directory unique to them. However it also occurs to me that you're just looking for a specific file. Let me rewrite that code in it's entirety so that you can look for a specific file, without needing to know it's directory.Even though I have a solution to this problem, I'd still like to have this code. This time during the first run the computer hung. After rebooting I did the command and then a keyword, it then said that my keyword was not a directory. How am I supposed to search across multiple drives if I don't know what directory I need to find it in?
I'll edit this post when I finish it. Shouldn't be long.Make sure you edit that modem part to whatever side your wired modem is onlocal tArgs = {...} local modem = peripheral.wrap("right") local function findFile(fileName) local function recurFile(directory,searchTerm) for a,v in pairs(directory) do if fs.isDir(v) then local fnd = recurFile(fs.combine(directory,v),searchTerm) if fnd ~= nil then return fnd end elseif v == searchTerm then return {true,fs.combine(directory,v)} end end end for a,v in pairs(modem.getNamesRemote()) do if peripheral.getType(v) == "drive" then local found = recurFile(disk.getMountPath(v),fileName) if found ~= nil then return unpack(found) end end end end local found,path = findFile(tArgs[1]) if found then print(path) end
Posted 01 May 2015 - 04:34 AM
Small oversight on my spot, didn't do it all correctly.
local tArgs = {...}
local modem = peripheral.wrap("right")
local function findFile(fileName)
local function recurFile(directory,searchTerm)
for a,v in pairs(fs.list(directory)) do --# Error was here, forgot fs.list
if fs.isDir(v) then
local fnd = recurFile(fs.combine(directory,v),searchTerm)
if fnd ~= nil then
return fnd
end
elseif v == searchTerm then
return {true,fs.combine(directory,v)}
end
end
end
for a,v in pairs(modem.getNamesRemote()) do
if peripheral.getType(v) == "drive" then
local found = recurFile(disk.getMountPath(v),fileName)
if found ~= nil then
return unpack(found)
end
end
end
end
local found,path = findFile(tArgs[1])
if found then print(path) end
Posted 02 May 2015 - 01:56 PM
Attempted to search, but got this instead: "attempt to index ? (a nil value)"Small oversight on my spot, didn't do it all correctly.local tArgs = {...} local modem = peripheral.wrap("right") local function findFile(fileName) local function recurFile(directory,searchTerm) for a,v in pairs(fs.list(directory)) do --# Error was here, forgot fs.list if fs.isDir(v) then local fnd = recurFile(fs.combine(directory,v),searchTerm) if fnd ~= nil then return fnd end elseif v == searchTerm then return {true,fs.combine(directory,v)} end end end for a,v in pairs(modem.getNamesRemote()) do if peripheral.getType(v) == "drive" then local found = recurFile(disk.getMountPath(v),fileName) if found ~= nil then return unpack(found) end end end end local found,path = findFile(tArgs[1]) if found then print(path) end
Posted 02 May 2015 - 03:34 PM
Just to make sure, you're calling the program with an extra word right?
Posted 02 May 2015 - 05:43 PM
Yes, I type the command (search) and then the keyword (gameoflife, on one of my drives). So I enter search gameoflife. I've also tried searching for other keywords, but it doesn't work.Just to make sure, you're calling the program with an extra word right?
Posted 02 May 2015 - 06:13 PM
And the modem is on the right?
Posted 02 May 2015 - 07:52 PM
Yes. If a red ring means on then yes, it is on.And the modem is on the right?
Posted 02 May 2015 - 09:16 PM
Please post the full error, uncluding the line number.
Posted 03 May 2015 - 03:27 AM
Played around with the code, ended up with a different result, what am I doing wrong here? https://www.dropbox.com/s/wubbzrcrwxqck1l/snip3.JPG?dl=0Please post the full error, uncluding the line number.
Edited on 03 May 2015 - 01:27 AM
Posted 03 May 2015 - 11:57 PM
Ugh, it's not your fault. Silly getMountPath returns nil if you don't have a floppy in it. Give me a minute to fix it again with the correct line.
local tArgs = {...}
local modem = peripheral.wrap("right")
local function findFile(fileName)
local function recurFile(directory,searchTerm)
for a,v in pairs(fs.list(directory)) do --# Error was here, forgot fs.list
if fs.isDir(v) then
local fnd = recurFile(fs.combine(directory,v),searchTerm)
if fnd ~= nil then
return fnd
end
elseif v == searchTerm then
return {true,fs.combine(directory,v)}
end
end
end
for a,v in pairs(modem.getNamesRemote()) do
if peripheral.getType(v) == "drive" and disk.hasData(v) then --# this should fix the problem
local found = recurFile(disk.getMountPath(v),fileName)
if found ~= nil then
return unpack(found)
end
end
end
end
local found,path = findFile(tArgs[1])
if found then print(path) end
Edited on 03 May 2015 - 09:58 PM
Posted 04 May 2015 - 04:01 AM
Success! Thanks to all who helped with this, I do appreciate it. If need be, I could end up helping you, just not with coding (Building something cool). But anyway, thanks again! https://www.dropbox.com/s/yxzb3jxdncir435/snip4.JPG?dl=0Ugh, it's not your fault. Silly getMountPath returns nil if you don't have a floppy in it. Give me a minute to fix it again with the correct line.local tArgs = {...} local modem = peripheral.wrap("right") local function findFile(fileName) local function recurFile(directory,searchTerm) for a,v in pairs(fs.list(directory)) do --# Error was here, forgot fs.list if fs.isDir(v) then local fnd = recurFile(fs.combine(directory,v),searchTerm) if fnd ~= nil then return fnd end elseif v == searchTerm then return {true,fs.combine(directory,v)} end end end for a,v in pairs(modem.getNamesRemote()) do if peripheral.getType(v) == "drive" and disk.hasData(v) then --# this should fix the problem local found = recurFile(disk.getMountPath(v),fileName) if found ~= nil then return unpack(found) end end end end local found,path = findFile(tArgs[1]) if found then print(path) end