I am working on a MacOS Big Sur 11.6 with R version 4.0.4 (2021-02-15)
I am trying to use paste() within a for loop but I need the values within the paste function to change with each iteration.
I have a data frame like this:
pathname S
1 user/folder/photo1 A
2 user/folder/photo2 B
3 user/folder/photo3 C
and I am trying to add an EXIF Comment tag to the metadata of my photos. I would like the Comment tag to change based on the S column value. I have code like this:
for(i in df$pathname){
x <- df$S[i]
sysCommand <- paste("exiftool -Comment=x i")
system(sysCommand)
}
The inputs (i.e. x and i) within the paste function should change as it goes through the list.
Thank you for your help!
Your interpretation of paste()
is flawed. This function takes R objects and concatenates their string representations.
So given
name <- "Rogue"
then the code
paste("Hi name!", " How are you?")
will simply concatenate the string objects "Hi name!"
and " How are you?"
to yield
[1] "Hi name! How are you?"
To substitute in the name
, one must use the name
object
paste("Hi ", name, "!", " How are you?")
# ^^^^
to obtain
[1] "Hi Rogue! How are you?"
paste()
CorrectlyAs the comments rightly suggest, the proper use of paste()
would be
# ...
sysCommand <- paste("exiftool -Comment=", x, " ", i, sep = "")
# ^^^^^^^^
# Avoid unwanted spaces.
# ...
with care to include the argument sep = ""
, and thus avoid extra spaces like those in "exiftool -Comment= A 1"
. Each result should look like this:
[1] "exiftool -Comment=A 1"
The paste0()
function omits extra spaces automatically, so it has no need for sep = ""
.
glue
PackageTo make things work the way you expected, you could use the glue
package.
# ...
sysCommand <- glue::glue("exiftool -Comment={x} {i}")
# ...
with care to "embrace" every variable name with { }
. Each result should look like
exiftool -Comment=A 1
a glue
object that is also a normal string.
As I mention in my comment
You've extracted your data incorrectly with
for(i in df$pathname)
anddf$S[i]
. When you usei
indf$pathname
, you're iterating withi
over the strings"user/folder/photo1"
,"user/folder/photo2"
, and so forth. By contrast,df$S[i]
expects a number within the[ ]
, as it attempts to take the value in thei
th place of columnS
. Since it can't interpret a string like"user/folder/photo1"
as anumeric
index, the operationdf$S[i]
returns anNA
value...whichpaste()
interprets as the string"NA"
.
your original code also erred logically when accessing the data in df
. The nifty answer by @dave2e offers a cleanly vectorized solution to this error.
That said, your correction does well in fixing this issue
for(i in 1:length(df$pathname)){
#for each photo
x <- df$S[i]
pathname <- df$pathname[i]
syscommand <- paste("exiftool -Comment=", site, " ", pathname, sep = "")
system(syscommand)
}
and it retains the structure of your original loop. I'm happy to hear it works!