Skip to contents

This article is meant for iRODS users familiar with iCommands, the command-line interface to iRODS. While rirods functions are based on iCommands, not all iCommands are covered and some functionality may differ. The article also compares the bash calls to the R calls in case the reader is not so familiar with R syntax.

The table below lists the main functions available in rirods and their counterparts in iCommands.

rirods iCommands
icd() icd
ipwd() ipwd
ils() ils
iget(), ireadRDS() iget
iput(), isaveRDS() iput
imeta() imeta
iquery() iquest
imkdir() imkdir
irm() irm

A general note is that in iCommands the -h argument provides the documentation for a certain command (e.g. icd -h), whereas in R this is achieved by preceding the name of the function with ? (e.g. ?icd). Moreover, the verbose boolean argument in most of rirods commands is used to print information about the HTTP request and response (and is by default FALSE), which is not a behaviour relevant to iCommands.

Working directory and collections

The iCommand ipwd and its rirods counterpart ipwd() work exactly the same, providing the path to the current working directory. The case of icd() is different; unlike icd, which returns the “/zone/home” directory if no argument is provided, icd() needs an argument with the path for a new working directory. icd("/tempZone/home") will take us to "/tempZone/home" like icd might, but icd() with no arguments will throw an error.

When it comes to listing the contents of a collection, both ils and ils() can be given a path, and if they are not, they list the contents of the working directory. Permissions can be shown by ils with the -A argument and by ils() by providing permissions=TRUE, although the latter does not return information about inheritance1. The time that the item was last modified and the size of data objects is shown by ils -l and by ils(stats=TRUE).

ils() # ils
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                         logical_path        type
#>  /tempZone/home/rods/some_collection  collection
#>   /tempZone/home/rods/200numbers.rds data_object
ils("some_collection") # ils some_collection
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>       /tempZone/home/rods/some_collection/subcollection  collection
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object
ils("some_collection", stat=TRUE) # ils -l some_collection
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>       /tempZone/home/rods/some_collection/subcollection  collection
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object
#>      last_write_time size
#>  2023-11-20 17:27:35   NA
#>  2023-11-20 17:27:35  831
ils("some_collection", permissions=TRUE) # ils -A some_collection
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type rods
#>       /tempZone/home/rods/some_collection/subcollection  collection  own
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object  own
ils(permissions=TRUE, stat=TRUE) # ils -Al
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                         logical_path rods        type     last_write_time size
#>  /tempZone/home/rods/some_collection  own  collection 2023-11-20 17:27:35   NA
#>   /tempZone/home/rods/200numbers.rds  own data_object 2023-11-20 17:27:36 1631

A crucial difference between ils and ils() is that ils(metadata=TRUE) is used to print the metadata information of each element listed, whereas iCommands only provides metadata information of one element at a time by calling imeta ls on it. At the moment, rirods does not offer any fast way of restricting the metadata to a specific item, although the custom function filter_ils() shown below could be used to achieve this result.

filter_ils <- function(pattern, ils_output = ils()) {
  stopifnot(inherits(ils_output, "irods_df"))
  ils_df <- as.data.frame(ils_output)
  if (length(pattern) == 1) {
    filtered <- ils_df[grepl(pattern, ils_df$logical_path),]
  } else {
    filtered <- ils_df[basename(ils_df$logical_path) %in% pattern,]
  }
  rirods:::new_irods_df(filtered)
}
my_files <- ils("some_collection", metadata=TRUE)
my_files
#> 
#> ========
#> metadata
#> ========
#> /tempZone/home/rods/some_collection/subcollection :
#> data frame with 0 columns and 0 rows
#> 
#> /tempZone/home/rods/some_collection/random_numbers.rds :
#>     attribute  value units
#>  distribution normal      
#>        length    100 items
#> 
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>       /tempZone/home/rods/some_collection/subcollection  collection
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object
filter_ils("random", my_files) # imeta ls -d some_collection/random_numbers.rds
#> 
#> ========
#> metadata
#> ========
#> /tempZone/home/rods/some_collection/random_numbers.rds :
#>     attribute  value units
#>  distribution normal      
#>        length    100 items
#> 
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object

Creating and deleting collections or data objects

With iCommands we can create new collections and data objects with imkdir and itouch respectively. The former is matched in rirods by imkdir(), but the latter is not covered by the R package yet.

Both in iCommands and in rirods, imkdir() requires a path and has an argument to request creating the parent collections:

imkdir("new_collection") # imkdir new_collection
ils()
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                         logical_path        type
#>   /tempZone/home/rods/new_collection  collection
#>  /tempZone/home/rods/some_collection  collection
#>   /tempZone/home/rods/200numbers.rds data_object

# imkdir -p another_collection/subcollection
imkdir("another_collection/subcollection", create_parent_collections = TRUE)

ils()
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                            logical_path        type
#>  /tempZone/home/rods/another_collection  collection
#>      /tempZone/home/rods/new_collection  collection
#>     /tempZone/home/rods/some_collection  collection
#>      /tempZone/home/rods/200numbers.rds data_object
ils("another_collection")
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                          logical_path       type
#>  /tempZone/home/rods/another_collection/subcollection collection

Removing data objects and collections can be achieved by irm in iCommands and irm() in rirods, and both functions have a force and recursive arguments:

irm("200numbers.rds", force = FALSE) # irm 200numbers.rds
ils("/tempZone/trash/home/rods")
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                              logical_path        type
#>  /tempZone/trash/home/rods/200numbers.rds data_object

irm("another_collection", force = TRUE, recursive = TRUE) # irm -rf another_collection
iquery("SELECT COLL_NAME WHERE COLL_NAME LIKE '%_collection'")
#>                                           COLL_NAME
#> 1                /tempZone/home/rods/new_collection
#> 2               /tempZone/home/rods/some_collection
#> 3 /tempZone/home/rods/some_collection/subcollection

Getting and putting data

In order to transfer data between a local system and iRODS, the main iCommands are iput and iget, which have iput() and iget() as rirods counterparts. The rirods functions are much more restricted in that they don’t really offer the variety of arguments that the iCommands do, but only options related to the HTTP requests. Moreover, they require the user to provide both the local and logical paths explicitly, whereas the iCommands reuse the source path by default. In other words, while iput myfile.txt will take a local file “myfile.txt” and store it in the iRODS working directory as “myfile.txt”, iput("myfile.txt") will throw an error; iput("myfile.txt", "myfile.txt") is the correct syntax to achieve the desired effect:

rirods iCommands Result
iget("myfile.txt", "myfile.txt") iget myfile.txt “myfile.txt” is copied from iRODS to local as “myfile.txt”
iget("myfile.txt", "another_path/filename.txt") iget myfile.txt another_path/filename.txt “myfile.txt” is copied from iRODS to local as “filename.txt” in “another_path”
iput("data.csv", "data.csv") iput data.csv “data.csv” is copied from local to iRODS as “data.csv”
iput("data.csv", "data2.csv") iput data.csv data2.csv “data.csv” is copied from local to iRODS as “data2.csv”

Next to these functions, rirods provides two functions to store R objects directly into iRODS or read RDS files directly from iRODS: isaveRDS() and ireadRDS(). There is no counterpart in iCommands. To achieve the same effect as isaveRDS(), a user would first have to save their object with saveRDS(), then send it to iRODS with iput and finally remove it with irm -f; in the same vein, the effect of ireadRDS() would be achieved by retrieving the file with iget, reading it with readRDS() and then removing it from the local space. Read more about this in vignette("local-irods").

Metadata and querying

The rirods imeta() function covers two of the main functionalities of the imeta iCommand: adding and removing metadata from a data object or collection. This function has three main arguments: the logical path of the data object or collection on which to add the metadata, the entity type (e.g. “data_object”, the default, or “collection”) and a list of operations, in which it is specified whether a certain AVU should be added or removed.

icd("some_collection")
ils(metadata=TRUE)
#> 
#> ========
#> metadata
#> ========
#> /tempZone/home/rods/some_collection/subcollection :
#> data frame with 0 columns and 0 rows
#> 
#> /tempZone/home/rods/some_collection/random_numbers.rds :
#>     attribute  value units
#>  distribution normal      
#>        length    100 items
#> 
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>       /tempZone/home/rods/some_collection/subcollection  collection
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object

# imeta add -C subcollection foo bar baz
imeta("subcollection", "collection",
      operations = list(
        list(operation="add", attribute="foo", value="bar", units="baz")
        )
      )

# imeta rm -d random_numbers.rds distribution normal
imeta("random_numbers.rds",
      operations = list(
        list(operation="remove", attribute="distribution", value="normal")
      ))

ils(metadata=TRUE)
#> 
#> ========
#> metadata
#> ========
#> /tempZone/home/rods/some_collection/subcollection :
#>  attribute value units
#>        foo   bar   baz
#> 
#> /tempZone/home/rods/some_collection/random_numbers.rds :
#>  attribute value units
#>     length   100 items
#> 
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>       /tempZone/home/rods/some_collection/subcollection  collection
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object

In order to “modify” an AVU with rirods, we would have to remove it and add its replacement. This also illustrates how we can add/remove several AVUs in one imeta() call, which would not be possible with imeta2.

# imeta mod -d random_numbers.rds length 100 items u:elements
imeta("random_numbers.rds",
      operations = list(
        list(operation="remove", attribute="length", value="100", units="items"),
        list(operation="add", attribute="length", value="100", units="elements")
      ))
ils(metadata=TRUE)
#> 
#> ========
#> metadata
#> ========
#> /tempZone/home/rods/some_collection/subcollection :
#>  attribute value units
#>        foo   bar   baz
#> 
#> /tempZone/home/rods/some_collection/random_numbers.rds :
#>  attribute value    units
#>     length   100 elements
#> 
#> 
#> ==========
#> iRODS Zone
#> ==========
#>                                            logical_path        type
#>       /tempZone/home/rods/some_collection/subcollection  collection
#>  /tempZone/home/rods/some_collection/random_numbers.rds data_object

As mentioned before, whereas the iCommand imeta ls is used to list the metadata of an item, ils(metadata=TRUE) is used in rirods instead.

Finally, the rirods equivalent of iCommand iquest is iquery(), with the same GenQuery expression as main argument and a few compatible arguments. Given a query variable such as “SELECT DATA_NAME, DATA_CHECKSUM WHERE COLL_NAME LIKE ‘/tempZone/home/rods%’”:

rirods iCommands
iquery(query) iquest "$query"
iquery(query, case_sensitive = FALSE) iquest uppercase "$query"
iquery(query, distinct = FALSE) iquest no-distinct "$query"

To learn more about imeta() and iquery(), see vignette("metadata").