LinuxQuestions.org
Support LQ: Use code LQ3 and save $3 on Domain Registration
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - General
User Name
Password
Linux - General This Linux forum is for general Linux questions and discussion.
If it is Linux Related and doesn't seem to fit in any other forum then this is the place.

Notices

Reply
 
LinkBack Search this Thread
Old 09-13-2012, 02:49 AM   #1
chrisgti
Member
 
Registered: Mar 2009
Posts: 58

Rep: Reputation: 15
Shell script to get name of file, delete original file, rename blank file


Hi,

I've had a request to help out someone accomplish a task involving a load of files in a directory.

Essentially, what I need to achieve is along the lines of the following, for each file in the directory:

- Get the file name & assign to var
- delete the original file
- take a copy of a placeholder file (which we will just call placeholder.txt)and add .tmp extension
- rename the copy of the placeholder.txt.tmp file to the original file name based on the var

I have a few ideas but I am not sure where best to start and I am tripping up with my script so far - any pointers would be greatly appreciated

Thanks
 
Old 09-13-2012, 03:45 AM   #2
segmentation_fault
Member
 
Registered: Sep 2008
Location: Ioannina, Greece
Distribution: Gentoo
Posts: 332

Rep: Reputation: 54
Why don't you just overwrite the original file (using cp or even cat)? Is there a reason you want to delete it first?
 
Old 09-13-2012, 08:45 AM   #3
chrisgti
Member
 
Registered: Mar 2009
Posts: 58

Original Poster
Rep: Reputation: 15
Overwriting would also be an option so long as the file name stays the same - say for instance we have files 1.txt 2.txt ...... 10.txt

I need to loop through the directory, get each file name, and basically replace the file with that name with a placeholder file with the same name

It's a bit of an unusual request though admittedly

I have been trying to do some basic scripting but I am tripping up with the logic needed

I suppose another way would be to go through the directory, get all the file names (assign to array?), and then for each file do a cp placeholder.txt filename.txt, and then as you say...set it to overwrite the original

I would need to get the filename without the extension though, otherwise it would end up being file.txt.txt i guess..
 
Old 09-13-2012, 08:57 AM   #4
chrisgti
Member
 
Registered: Mar 2009
Posts: 58

Original Poster
Rep: Reputation: 15
Had a bit of a brainwave...and realise it's almost going to be as simple as a 1 liner:..my base for testing is now:

Code:
for i in $(ls) '*.txt'; do cp placeholder.txt $i; done
Sometimes it's just nice to be prompted to think about things a little differently

I will try that!
 
Old 09-13-2012, 09:19 AM   #5
segmentation_fault
Member
 
Registered: Sep 2008
Location: Ioannina, Greece
Distribution: Gentoo
Posts: 332

Rep: Reputation: 54
I recently read a post here on LQ about not using ls in such scripts. Instead use something like
Code:
for filename in *; do <something> done
Check this why.
 
Old 09-13-2012, 09:45 AM   #6
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,512
Blog Entries: 27

Rep: Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174
Safer to quote the $i in case its value contains something bash will substitute:
Code:
for i in *.txt; do cp placeholder.txt "$i"; done
 
Old 09-13-2012, 09:53 AM   #7
chrisgti
Member
 
Registered: Mar 2009
Posts: 58

Original Poster
Rep: Reputation: 15
Thanks for that article, I must admit I did not know that, and I will indeed follow your suggestion

However I am very close with the other way and I just want to fix it to understand where I am going wrong at the last hurdle:

I now have:

Code:
for i in $(ls | grep txt); do \cp ../placeholder.txt "$i"; done
And this works just fine, when I open a a TXT with the original file name, I can see that the new placeholder content is now there. EXCEPT for TXT files with spaces in the file names...and I then just see several files. For example. TXT WITH SPACES.TXT ends up looking like this in an ls:

TXT
SPACES.TXT
WITH

and also the original TXT WITH SPACES.txt

I have tried '$i' and "$i" - alas, no difference (though it does throw errors with just 'i', "i" works but the result is the same as above)

Last edited by chrisgti; 09-13-2012 at 09:55 AM.
 
Old 09-13-2012, 10:00 AM   #8
chrisgti
Member
 
Registered: Mar 2009
Posts: 58

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by catkin View Post
Safer to quote the $i in case its value contains something bash will substitute:
Code:
for i in *.txt; do cp placeholder.txt "$i"; done
Ah ha! That's got it, even with the spaces. Oddly I was tring for i in *.txt earlier today and I was getting errors that suggested it was looking inside the files, but I was obviously doing something wrong.

I am still curious to know then why when I use "$i" in the other command it doesn't work.

But thanks for the assistance, this has been way simpler than I first thought..and I learned something. Win, win!
 
Old 09-13-2012, 10:14 AM   #9
suicidaleggroll
Senior Member
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 2,408

Rep: Reputation: 883Reputation: 883Reputation: 883Reputation: 883Reputation: 883Reputation: 883Reputation: 883
Quote:
Originally Posted by chrisgti View Post
Thanks for that article, I must admit I did not know that, and I will indeed follow your suggestion

However I am very close with the other way and I just want to fix it to understand where I am going wrong at the last hurdle:

I now have:

Code:
for i in $(ls | grep txt); do \cp ../placeholder.txt "$i"; done
And this works just fine, when I open a a TXT with the original file name, I can see that the new placeholder content is now there. EXCEPT for TXT files with spaces in the file names...and I then just see several files. For example. TXT WITH SPACES.TXT ends up looking like this in an ls:

TXT
SPACES.TXT
WITH

and also the original TXT WITH SPACES.txt

I have tried '$i' and "$i" - alas, no difference (though it does throw errors with just 'i', "i" works but the result is the same as above)
It's because the for is splitting on spaces, your problem is the for i in $(ls | grep txt). If you had three files: a.txt, b.txt, and "c d.txt" (with a space), your "ls | grep txt" would spit out the single string "a.txt b.txt c d.txt". The for would then split on spaces, giving you "a.txt", "b.txt", "c", and "d.txt". This is why you want to do the for over *.txt directly, without throwing an intermediate ls in the middle. When you do "for i in *.txt" it will handle the spaces correctly. "for i in $(ls *.txt)" will not.
 
Old 09-14-2012, 03:42 AM   #10
chrisgti
Member
 
Registered: Mar 2009
Posts: 58

Original Poster
Rep: Reputation: 15
That all makes sense, thankyou

I've realised there is a final requirement - to make it work recursively

so I modified the one liner a bit after a bit of Googling:

Code:
#!/bin/bash
FILES=$(find folder_name -type f -name '*.txt')
for i in $FILES;
do
\cp placeholder.txt "$i";
done
This doesn't work with spaces either, so I tried

Code:
FILES="$(find folder_name -type f -name '*.txt')"
But apparently didn't make any difference...so, what am I missing?

Thanks
 
Old 09-14-2012, 04:22 AM   #11
segmentation_fault
Member
 
Registered: Sep 2008
Location: Ioannina, Greece
Distribution: Gentoo
Posts: 332

Rep: Reputation: 54
Maybe you should try something like
Code:
for file in *.txt; do cp placeholder.txt "$file"; done
If you want to use "find" for that check the "exec" part of find command and don't combine it with "for".
 
Old 09-15-2012, 02:49 AM   #12
catkin
LQ 5k Club
 
Registered: Dec 2008
Location: Tamil Nadu, India
Distribution: Servers: Debian Squeeze and Wheezy. Desktop: Slackware64 14.0. Netbook: Slackware 13.37
Posts: 8,512
Blog Entries: 27

Rep: Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174Reputation: 1174
Quote:
Originally Posted by chrisgti View Post
Code:
FILES="$(find folder_name -type f -name '*.txt')"
But apparently didn't make any difference...so, what am I missing?
It is the same issue. FILES is set to the output of find including whitespace. If you then use $FILES unquoted, bash turns it into a list of whitespace-separated words separated by spaces.

The classic robust idiom for looping over file names is:
Code:
while IFS= read -r -d '' file
do
   Do something with "$file"
done < <(find <whatever> -print0)
This search lists several examples of the above code.
.
This LQ post explains how it works.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Mencoder adds the extension of the original file to the output file ex: file.flv.mp4 linuxlicious Linux - General 2 04-17-2012 02:22 PM
Mencoder adds the extension of the original file to the output file ex: file.flv.mp4 linuxlicious Linux - General 1 04-15-2012 04:07 AM
text match pipe to file then delete from original text file create new dir automatic tr1px Linux - Newbie 6 09-10-2008 09:40 PM
how to rename a file and copy a file in a shell zach014 Linux - Newbie 6 11-23-2006 09:23 AM


All times are GMT -5. The time now is 11:41 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration