I'm working on a project in a shared Google Drive folder where we recently learned we need to change some strings, that are found in all the documents, with slightly different strings. There are hundreds of files, and it'd be impossible to go through them all one by one, and after some looking I found a Universal Find and Replace script.
https://ctrlq.org/code/19926-universal-find-replace-in-google-drive
Problem is, I have little to no experience with code and even with the instructions given on the site, I have no clue what I have to do with the script. All of it is gibberish to me, and I'd be unbelievably grateful if someone could walk me through all of it.
Questions:
Where in the script do I specify the Drive folder in question and how do I specify it? The "folder path" thing has me even more confused, so if you can let me know where exactly I can find the needed info, that would be great.
Where do I specify the strings I need to replace? I can obviously tell that doc.replaceText has something to do with it, but the fact that it says "You can use regex too" makes me curious if there's anything else I need to change before that?
How should I make a copy of the script code and where in my Google Drive do I place the file?
If there's any other steps I might be overlooking, please mention those as well.
Also, will it be possible to replace more than one string in a single script? (i.e change all "red" to "blue" and change all "black" to "white")
Thank you all in advance, this might end up being a lifesaver?
You might want to look at Apps Script's Drive Service and Document Service to help you be more familiar about the classes and functions to be used.
Drive Service
This service allows scripts to create, find, and modify files and folders in Google Drive.
Document Service
This service allows scripts to create, access, and modify Google Docs files.
Creating a Folder
Using the sample code :
// Log the name of every folder in the user's Drive.
var folders = DriveApp.getFolders();
while (folders.hasNext()) {
var folder = folders.next();
Logger.log(folder.getName());
}
You can set
var newFolder = DriveApp.createFolder('My New Folder');
//To check if you successfully created a folder
Logger.log(newFolder.getId())
//To set sub folder under "My New Folder"
var id = newFolder.getId()
var subFolder = newFolder.createFolder('New Sub Folder')
2. Where do I specify the strings I need to replace? I can obviously tell that doc.replaceText has something to do with it, but the fact that it says "You can use regex too" makes me curious if there's anything else I need to change before that?
You can use findText(searchPattern, from)
Searches the contents of the element for the specified text pattern, starting from a given search result.
A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.
The provided regular expression pattern is independently matched against each text block contained in the current element.
3. How should I make a copy of the script code and where in my Google Drive do I place the file?
You can use Apps Script Console to create your codes, this will be placed in you drive folder.
Lastly, here is a sample code that will change the color of the text:
var body = DocumentApp.getActiveDocument().getBody();
// Use editAsText to obtain a single text element containing
// all the characters in the document.
var text = body.editAsText();
// Insert text at the beginning of the document.
text.insertText(0, 'Inserted text.\n');
// Insert text at the end of the document.
text.appendText('\nAppended text.');
// Make the first half of the document blue.
text.setForegroundColor(0, text.getText().length / 2, '#00FFFF');
Hope it helps!
Related
New to Google Apps script here, but have some coding experience. I want to scan current folder for spreadsheets. For each spreadsheet found, I want to change the value in a specific cell (say cell F16 in "Sheet1") to "Q1 FY16". Here is what I have so far:
function myFunction() {
var folderID ="0BxfGszImm3D9flpVlWXd4bjQ";
var topFolder = DriveApp.getFolderById(folderID);
Logger.log(topFolder.getName());
var filesList = topFolder.getFiles();
while (filesList.hasNext()) {
var file = filesList.next();
Logger.log(file.getName());
file.getSheetByName("Sheet1").getRange("F16").setValue("Q1 FY16");
}
}
There are two main problems:
I have to specify a folder ID in this and I don't want to. I want the code to run in the current directory (and eventually I will make it recursive to scan all subfolders as well).
The File class doesn't have the "getSheetByName()" or "getRange()" methods, but I don't know how to cast the files into Spreadsheets.
Any help with this would be greatly appreciated.
Cheers
Where will you be launching this script from? They are no way of launching script directly from google drive.
to Be able to use the getSheetByName() and the getRange() you need to open the file as a spreadsheet.
instead of using this line:
file.getSheetByName("Sheet1").getRange("F16").setValue("Q1 FY16");
You should use something like this :
try {
SpreadsheetApp.openById(file.getId()).getSheetByName("Sheet1").getRange("F16").setValue("Q1 FY16");
}
catch(e){}
you need to use the try - catch since some of the files won't be spreadsheet and give and error when trying to use the SpreadsheetApp.openById().
I hope this helps you a bit, I'll try to update this answer once I get more information for the first part.
Best of luck.
This might seem like very basic stuff, but can somebody tell me what the purpose of this [0]; after the ("myfile3") in the code below does? I got it from the Google developers page but there is no explanation as to what it does. I am new to GAS and Javascript and don't have a lot of programming experience but all I am trying to do is copy a file on from my root drive in Google drive and then move it to another folder. Then code below works sometimes, but then after a while I get an error that tells me: "File copyFile must be converted to a Google document first. (line 5, file "copy")".
Any help appreciated. (Sorry if it is a stupid question)
The code is:
function copyFile()
{
var file = DocsList.find("myfile3")[0];
var copy = file.makeCopy("myfile5");
}
from the documentation : find(query) : Returns an array of all the files in the container that contain the given string.
Find() searches the content of all the files, not their names.
That means that you have to choose which element of the array you want to open... using [0] means you take the first result.
It might be the file you're looking for but it is not sure at all...
To narrow your search to the filename you should simply iterate the returned array while testing each file's name and pick up the one you want.
it might be in a for loop like this :
var files = DocsList.find("myfile3");
for(var f=0;f<files.length;++f){if(files[f].getName()==query){var foundDocId=file[f].getId() ; break}
From there use the file ID to access your file as this one is unique (names are not in Google Docs).
as simple as that ;-)
I would suggest testing the DriveApp version of this function for two implicit reasons:
The DocsList service is deprecated and may be discontinued as the
DriveApp functions are fleshed out.
DriveApp is a little more agnostic
when it comes to filetypes, and may bypass your error.
Check out fileMakeCopy() in the Apps Script Documents for details.
Is there a way to copy and rename a file and move that copy to a particular folder without having a second copy in the root folder? I have used combinations of copy, rename, move in different order, but each time, I still end up with a copy of the renamed file the root drive. Is this by default? It is annoying to say the least.
In the new version of google apps script all you need to acheive your task is the following:
file.makeCopy("new name", folder);
EDIT : I had a look at your original question (before edit) and from there I understood the confusion you made about how files and folders work in Google Drive.
When you make a copy of a file you get a new file in the root folder, when you add this new file to another folder you have to consider that as sticking a label on this file without creating any new copy of it.
You can actually see the file in both the root and the other folder but it is the very same file with 2 different labels! (and you did notice that since you tried to delete it and saw it was deleted in both places)
The only thing you have to do to get the new file in its folder and not shown in the root it to remove the "root label".
That's how Google drive works. And when you think about it and compare to a local hard disk storage it gets logical : when you move a file from one folder to another on the same logical drive you don't move data (ie the bytes on the disk) but simply tell the disk operating system that this file is somewhere else on the map.
So consider Google Drive as a (very) large disk unit with billions on files that you can't move but on which you can stick as many labels as you want ;-) (the most important label being your Google account ID !)
And to play with these labels in the case you describe just try this simple function :
function copyAndMove(file,folder){
var newfile=file.makeCopy('copy of '+file.getName());// here you can define the copy name the way you want...
newfile.addToFolder(folder);// add the copy to the folder
newfile.removeFromFolder(DocsList.getRootFolder());// and remove it from your root folder
}
to test it just use the 2 required parameters : the file object anf the folder object that you can get from many different methods, see the DocsList documentation for details on how to get it if you need to but I guess you already know that ;-)
Yeah, it is a bit odd that Google does not provide a move method. But, considering how drive works and that a file can belong to multiple folders, it makes some sense that you have write your own moves. Here is a simple move function I wrote:
// Moves a file to a new folder by removing all current
// parent folders and then adding the new one.
function moveFileTo(fileObj, folderObj) {
// Attempt the move only if folderObj has a value.
// Otherwise, the file will be left without a folder.
// (Lost files can be found in the "All items" area.)
if (folderObj) {
var folders = fileObj.getParents();
for (var i = 0; i < folders.length; i++) {
fileObj.removeFromFolder(folders[i]);
}
fileObj.addToFolder(folderObj);
return true;
}
return false;
}
Basically, use it like this:
var file = DocsList.getFileById(fileID);
var folder = DocsList.getFolder('Some folder name');
// Make a backup copy.
var file2 = file.makeCopy('BACKUP ' + Utilities.formatDate(new Date(), Session.getTimeZone(), 'yyyy-MM-dd') + '.' + file.getName());
// Move the backup file.
if (moveFileTo(file2, folder)) {
...
I should note that this simple function is exactly that... simple. It assumes you are okay with whacking all parent folders -- owned or shared. This can have unexpected consequences with shared files in various shared folders of various users if you are not careful. It does not appear, however, to remove parent folders that are not shared with the user of this script -- which is good. Anyhow, one obvious alternative to control things better would be to specify the "from" folder as well as the "to" folder.
I want to change the sharing 'visibility' of currently stored documents from 'anyone with the link may view' to 'private'. This is distinct from removing named viewers and editors.
Unfortunately, the GAS has a very limited support of the documents visibibility. There is no functionality to change this option for the DocsList.File and DocumentApp.Document classes. The Spreadsheet class has the setAnonymousAccess method using which is possible to set if a spreadsheet is public.
Please open a new feature request on the issue tracker if this feature is important for you.
There is an easy way to get what you want using a method that has already been mentioned in this post
You can set the sharing / visibility parameters of any document by moving it to a shared folder. If you remove it from the shared folder then it is no long shared and that is what you wanted to do didn't you ?
So all you need to do is not to use individual sharing parameters on files but rather use the folder structure to share your files.
As a reminder, the code could be something like this to add to the folder :
function sharebyFolder(){
var file = DocsList.getFileById('docId');
var folder = DocsList.getFolderById('shared folder Id');
file.addToFolder(folder)
}
and to remove it :
function UnsharebyFolder(){
var file = DocsList.getFileById('docId');
var folder = DocsList.getFolderById('shared folder Id');
file.removeFromFolder(folder)
}
The old docs API offers a good solution:
https://developers.google.com/google-apps/documents-list/#removing_sharing_permissions
I am trying to utilize Google Drive as repository for many different types of documents. I have those documents arranged in several different folders.
When I perform a search it seems to search my entire Google Drive account for matching results regardless of the fact that I am currently within a specific folder.
This poses a problem for me as I want to be able to refine my searches to within a given grouping of documents.
If I am searching for documents related to my work, for instance, I don't want documents showing up in my search that are personal, or in my personal directories.
Is there a way to refine my search to only show documents within a specified folder and it's subfolders? I know I can refine the search based on file type and ownership, but that doesn't work for me.
Thanks in advance.
Using the Google Drive SDK, you can perform a search query for <folder_id> in parents.
The code I have included allows me to search the body of files within a specific folder. I am using it to search scanned documents and will have it move the file to another folder based on search criteria I specify.
The great thing about this is that it will search the body of the document and return all documents that meet your search criteria. As you can see I can also specify a date range and you can use other operators to define your search. https://developers.google.com/drive/web/search-parameters.
This was a great find for me and I hope it can help some others.
function searchFolder(){
var parent = DriveApp.getFolderById(‘*******************’); // folder Id
var search = 'modifiedDate >"2014-08-01" and modifiedDate < "2014-12-31" and fullText contains "PUT SEARCH TEXT HERE"';
var specificFolder = parent.searchFiles(search);
while (specificFolder.hasNext()) {
var file = specificFolder.next();
Logger.log(file.getName());
Logger.log(file.getId());
}
}
As far as I know you'd have to do this for each subfolder, but the API (and my app) will search by folder.
I wrote an app that uses the API to search by folder. It is a bit slow so be patient when it is loading.
https://script.google.com/macros/s/AKfycby6G32K-vKCiLmoKvMtG64cYPHEREEx1PY5IoYrEYaR6WAfbXs/exec
// -----------------
var sr = DocsList.getFolder("temp_scripts").find("var");
var i = 0;
for(i=0;i<sr.length;i++)
{
var r = sr[i];
Logger.log('name='+r.getName());
Logger.log('parent=' +r.getParents()[0].getName() );
Logger.log('---');
}
// -----------------
I found a sort of workaround using the description field.
In my particular case, all the files created in the folder i want to search are created programmatically by my own script, but is quite simple to write a script to (re)define the description field into all the files in a specific folder using .setDescription(DESCRIPTION). Once this is done...
The good news is that the standard search in google drive give results based on the description field, including the value set on it into the search field (plus any data you want to find into those files) you will get the results you need.
Of course you need to scarify the description field (or, at least, overcrowd it;-)
As, I think all of you, I'm still waiting for the folder keyword in the standard serch field.
I implemented the function in this Chrome Extension.
https://chrome.google.com/webstore/detail/advanced-drive-search/chomjcpadndbjgkanbaakmjehdoighab
You can check the code here
https://github.com/kissrobber/advanced_google_drive_search_chrome_extension
What that do is
get all the folders
build a query with the folder_id and the descendant folder_ids. Like this (<folder_id> in parents or <folder_id> in parents or ....)
If you have concern with the performance, try the Chrome extension.
There is another workaround that do NOT require any third party app or extension.
Remove your folder (In which you wanna search something)
Search with is:trashed filter. For example: is:trashed query_string
Restore your folder back