search and replace

Questions about using NAS on Mac OS.
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

Hi and welcome to the forum. :)
monkeyfreak2 wrote: Tue Mar 26, 2019 11:02 pm The command seems to run without a hitch, but the file names of the files I am trying to change dont seem to actually do anything at all. Could you explain what you mean by double quoting a variable and what that would look like at the end? Sorry, I am very much a novice. Below is my code.

Code: Select all

[/share/Resources/Training/Evan] # for f in $(find /share/Resources/Training/Evan/ -name "*:*"); do mv "$f" "${f/:/_}"; done
You've correctly double-quoted the variable I mentioned. Good work. :geek:

If you're already in the [/share/Resources/Training/Evan] directory, you won't need to specify that path again as an argument to 'find'. Instead, use a single period to indicate "this directory".

e.g.

Code: Select all

[/share/Resources/Training/Evan] # for f in $(find . -name "*:*"); do mv "$f" "${f/:/_}"; done
Let's examine and test on a single filename for now. Can you please provide a file list of that directory's contents?

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
monkeyfreak2
New here
Posts: 3
Joined: Tue Mar 26, 2019 10:57 pm

Re: search and replace

Post by monkeyfreak2 »

Thank you :geek:

Well, actually I was wrong with that file path.. my bad. But when I correct the file path, I do find a lot of files, and they are the files I would like corrected.

However, when I enter in the code below, I get a long line of lines of files that say for example
mv: can't rename 'Reports/1234/6:27:16': No such file or directory

Code: Select all

[/share/Reports] # for f in $(find /share/Reports/ -name "*:*"); do mv "$f" ${f/:/_}; done

As for isolating one file, I will pick the one I just used for that example. /share/Reports/Cust PDF Reports/1234/6:27:16

So when I enter

Code: Select all

[/share/Reports/Cust PDF Reports/1234] # find .  -name "*:*"
I get all the files (in this folder) that I am looking for. The obvious issue is that when I type in the code from before, I get "Reports/acct number/file date" and not the correct value which would have been "Reports/Cust PDF Reports/acct number/file date", and there are a lot more account numbers to deal with so I am hoping to be able to set up a more general case command to enter. But for now I'm ignoring that and am going to work through what you asked me to.

In this example I get the files listed as follows
./2:22:2017
./4:26:18
./6:27:16
./Essen 5:31:16

Then I entered in

Code: Select all

[/share/Reports/Cust PDF Reports/1234] # for f in $(find .  -name "*:*"); do mv "$f" ${f/:/_}; done
and it worked! sort of..
1) as you can see there is a space in one of the file names, which is fine as far as I am concerned, however I got two errors that it cant rename a file called "./Essen" and that it cannot rename a file named "./5:31:16" "No such file or directory". and I am unsure how to circumvent this, I believe I would have to put quotation marks around the file name, but am not sure where to do that with all the variable stuff that is unfamiliar to me so far.

2) When I use the find command now for this directory I get the following. (at this point i could just use ls as these are the only files in this directory anyway, but new skills are fun to practice.)

Code: Select all

[/share/Reports/Cust PDF Reports/1234] # find .  -name "*:*"  
./2_22:2017
./4_26:18
./6_27:16
./Essen 5:31:16

PROGRESS!!

Now out of curiosity I ran the following code again

Code: Select all

[/share/Reports/Cust PDF Reports/1234] # for f in $(find .  -name "*:*"); do mv "$f" ${f/:/_}; done
and it worked.. again! Other than that file with the space in it, now nothing shows up for the find function but that file, and when I do ls. its exactly what I was looking for.

2_22_2017
4_26_18
6_27_16
Essen 5:31:16


So first off, thank you so much!! I have learned a lot in this exercise with your help! I was, however, hoping that you could answer some follow up questions that I encountered along the way.

1) getting a method that can reliably find all files/folders within a larger directory(/share/Reports/Cust PDF Reports/) that includes sub directories(individual account numbers, all 4 digit) which in turn contain the file/folder that I want to change the name of. I only have a couple hundred, so it would not be the worst thing in the world to do it manually for each account number if its what I need to do.
2) file names with spaces, help please
3) is there a way to get this to run lets say 5 times on its own in case there are many colons in one name? This is just for my own curiosity in learning terminal, I am more than willing to hit up and enter 5 times :lol:

as for 1, I attempted just going for this and still got all the "no such file or directory" stuff from before.

Code: Select all

[/share/Reports/Cust PDF Reports] # for f in $(find .  -name "*:*"); do mv "$f" ${f/:/_}; done
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

As you'd like to replace multiple copies of that character, your character replacement should be 'global'. Add an extra forward-slash. This ensures BASH won't stop after matching the first occurrence of the ':' character (and means you won't need to run the same command multiple times to replace each copy):

Code: Select all

${f//:/_}
To handle filename whitespace correctly, we must ensure BASH doesn't perform word-splitting on the output generated by 'find'. So, we'll double-quote that output:

Code: Select all

"$(find . -name "*:*")"
To ensure 'mv' writes the output filename correctly (with whitespace), we'll also double-quote the target filename:

Code: Select all

"${f//:/_}"
If you put it all together:

Code: Select all

for f in "$(find . -name "*:*")"; do mv "$f" "${f//:/_}"; done
Can you please try this and advise if it's getting closer to what you need?

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
monkeyfreak2
New here
Posts: 3
Joined: Tue Mar 26, 2019 10:57 pm

Re: search and replace

Post by monkeyfreak2 »

Closer, yes. The problem that I think is happening now, is that when I run that on a smaller folder to test it, I got this output:

mv: cant rename './9_27:17
./another folder 1:23:45
./another folder 1:23:46
./etc' : No such file or directory, so has putting quotes around something caused it to group all of these names together?

I did some reading on IFS, so I tried changing it from the whitespace value to IFS=$'\n'

Code: Select all

IFS=$'\n' ; for f in $(find . -name "*:*"); do mv "$f" ${f//:/_}; done
And it worked! woot! Thanks for all your help!
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

Nicely done. :D

Yes, setting the IFS is the right way to go (but I was trying to avoid it). I stopped using whitespace in filenames long ago, so I've gotten a little rusty with regard to processing filenames containing spaces. :lol:

Don't forget to return $IFS to its original value afterward if your script will be processing anything else.

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
pbart
Know my way around
Posts: 109
Joined: Thu Feb 28, 2013 12:36 am

Re: search and replace

Post by pbart »

Hello OneCD,
still try to figure out how to change ":" to "_" in files names.

I tried what you suggested:
OneCD wrote: Fri Jul 07, 2017 7:02 pm You'll need to append demofind with a trailing forward slash:

Code: Select all

for f in $(find /share/Public/demofind/ -name "*:*"); do mv $f ${f/:/_}; done
...but got these errors:
[/share/Public] # for f in $(find /share/Public/demofind/ -name "*:*"); do mv $f ${f/:/_}; done
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `01:03:19.pdf': No such file or directory
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `06:09:19.pdf': No such file or directory
[/share/Public] # for f in $(find /share/Public/demofind/ -name "*:*"); do mv $f ${f/:/_}; done
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `01:03:19.pdf': No such file or directory
mv: unable to rename `/share/Public/demofind/Redazionali': No such file or directory
mv: unable to rename `06:09:19.pdf': No such file or directory
By the way, the files I'm trying to rename have these kind of syntax:
"Redazionali 06:09:19.pdf"

What am I missing in the script, why it fails ?
Paolo Bartoli
----------------
various Mac OS X 11 to 13
QNAP TS251 /QTS 5.1.0.2444
QNAP TS219PII /QTS 4.3.3.242
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

pbart wrote: Fri Jan 14, 2022 6:00 pm Hello OneCD,
still try to figure out how to change ":" to "_" in files names.
Sorry, I forgot to respond to this one. :oops:

Please ensure you double-quote the loop variable:

Code: Select all

for f in "$(find . -name "*:*")"; do mv "$f" "${f//:/_}"; done
Another way (as-suggested by @monkeyfreak2 earlier) - set the IFS to a newline char first:

Code: Select all

IFS=$'\n' ; for f in $(find . -name "*:*"); do mv "$f" ${f//:/_}; done

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
pbart
Know my way around
Posts: 109
Joined: Thu Feb 28, 2013 12:36 am

Re: search and replace

Post by pbart »

OneCD, I think I'm stuck with some syntax error.
Try this out, I get this error:

Code: Select all

# for f in "$(find . -name "*:*")"; do mv "$f" "${f//:/_}"; done
mv: unable to rename `': No such file or directory
OneCD wrote: Sun Jan 16, 2022 5:39 am
pbart wrote: Fri Jan 14, 2022 6:00 pm Hello OneCD,
still try to figure out how to change ":" to "_" in files names.
Sorry, I forgot to respond to this one. :oops:

Please ensure you double-quote the loop variable:

Code: Select all

for f in "$(find . -name "*:*")"; do mv "$f" "${f//:/_}"; done
Another way (as-suggested by @monkeyfreak2 earlier) - set the IFS to a newline char first:

Code: Select all

IFS=$'\n' ; for f in $(find . -name "*:*"); do mv "$f" ${f//:/_}; done
Paolo Bartoli
----------------
various Mac OS X 11 to 13
QNAP TS251 /QTS 5.1.0.2444
QNAP TS219PII /QTS 4.3.3.242
pbart
Know my way around
Posts: 109
Joined: Thu Feb 28, 2013 12:36 am

Re: search and replace

Post by pbart »

I've found that this script works:

Code: Select all

for f in $(find /share/Public/ -name "*:*"); do mv $f ${f/:/_}; done
but if the filenames contain spaces (whitespace), It doesn't work.

Code: Select all

for f in $(find /share/HD\ \Server/disegni@Quickserver/\ \BARTOLI_DESIGN/COMUNICAZIONE/rass\ \stampa\ \MdiP/2019 -name "*:*"); do mv $f ${f/:/_}; done

mv: unable to rename `/share/HD': No such file or directory
mv: unable to rename `Server/disegni@Quickserver/': No such file or directory
mv: unable to rename `BARTOLI_DESIGN/COMUNICAZIONE/rass': No such file or directory
mv: unable to rename `stampa': No such file or directory
mv: unable to rename `MdiP/2019/Redazionali': No such file or directory
mv: unable to rename `11:01:19.pdf': No such file or directory
 etc.
How do I manage whitespace in filenames ?
Paolo Bartoli
----------------
various Mac OS X 11 to 13
QNAP TS251 /QTS 5.1.0.2444
QNAP TS219PII /QTS 4.3.3.242
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

pbart wrote: Tue Jan 18, 2022 1:32 am How do I manage whitespace in filenames ?
Try the other method shown earlier: set the IFS first. ;)

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
pbart
Know my way around
Posts: 109
Joined: Thu Feb 28, 2013 12:36 am

Re: search and replace

Post by pbart »

I tired the suggested one as:

Code: Select all

IFS=$'\n' ; for f in $(find . /share/HD\ \Server/disegni@Quickserver/\ \BARTOLI_DESIGN/COMUNICAZIONE/rass\ \stampa\ \MdiP/2019 "*:*"); do mv "$f" ${f//:/_}; done
but again run into errors:
mv: unable to rename `.': Device or resource busy
mv: unable to rename `/share/HD Server/disegni@Quickserver/ BARTOLI_DESIGN/COMUNICAZIONE/rass stampa MdiP/2019': Invalid argument
mv: unable to rename `/share/HD Server/disegni@Quickserver/ BARTOLI_DESIGN/COMUNICAZIONE/rass stampa MdiP/2019/Redazionali 24:05:19.rtfd/TXT.rtf': No such file or directory
mv: unable to rename `/share/HD Server/disegni@Quickserver/ BARTOLI_DESIGN/COMUNICAZIONE/rass stampa MdiP/2019/Redazionali 29_04_19.rtfd': Invalid argument
??
Paolo Bartoli
----------------
various Mac OS X 11 to 13
QNAP TS251 /QTS 5.1.0.2444
QNAP TS219PII /QTS 4.3.3.242
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

pbart wrote: Tue Jan 18, 2022 7:13 pm I tired the suggested one as:

Code: Select all

IFS=$'\n' ; for f in $(find . /share/HD\ \Server/disegni@Quickserver/\ \BARTOLI_DESIGN/COMUNICAZIONE/rass\ \stampa\ \MdiP/2019 "*:*"); do mv "$f" ${f//:/_}; done
You've specified the 'find' arguments incorrectly.

Try this: change into your target directory first:

Code: Select all

cd /share/HD\ \Server/disegni@Quickserver/\ \BARTOLI_DESIGN/COMUNICAZIONE/rass\ \stampa\ \MdiP/2019
... then run the following command exactly as-shown (don't edit it):

Code: Select all

IFS=$'\n'; for f in $(find . -name "*:*"); do mv "$f" "${f//:/_}"; done

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
pbart
Know my way around
Posts: 109
Joined: Thu Feb 28, 2013 12:36 am

Re: search and replace

Post by pbart »

OneCD, thanks !!

It works !! :DD
Paolo Bartoli
----------------
various Mac OS X 11 to 13
QNAP TS251 /QTS 5.1.0.2444
QNAP TS219PII /QTS 4.3.3.242
User avatar
OneCD
Guru
Posts: 12136
Joined: Sun Aug 21, 2016 10:48 am
Location: "... there, behind that sofa!"

Re: search and replace

Post by OneCD »

Excellent. :geek:

ImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImageImage
Locked

Return to “Mac OS”