Batch replace text inside text file (Linux/OSX Commandline) - unix

I have hundreds of files where I need to change a portion of its text.
For example, I want to replace every instance of "http://" with "rtmp://" .
The files have the .txt extention and are spread across several folders and subfolder.
I basically am looking for a way/script that goes trough every single folder/subfolder and every single file and if it finds inside that file the occurrence of "http" to replace it with "rtmp".

You can do this with a combination of find and sed:
find . -type f -name \*.txt -exec sed -i.bak 's|http://|rtmp://|g' {} +
This will create backups of each file. I suggest you check a few to make sure it did what you want, then you can delete them using
find . -name \*.bak -delete

Here's a zsh function I use to do this:
change () {
from=$1
shift
to=$1
shift
for file in $*
do
perl -i.bak -p -e "s{$from}{$to}g;" $file
echo "Changing $from to $to in $file"
done
}
It makes use of the nice Perl mechanism to create a backup file and modify the nominated file. You can use the above to iterate through files thus:
zsh$ change http:// rtmp:// **/*.html
or just put it in a trivial #!/bin/zsh script (I just use zsh for the powerful globbing)

Related

Remove last line from all files of a specific extension

I have several files with same extension .txt in a directory. I want to remove the last line from all .txt files.
What I did is
find . -type f -name '*.txt' -exec sed '$d' {} \;
This prints the desired output from sed to the terminal for every .txt file.
What I want is to modify the respective files.
Try this:--
sed -i '$d' *.txt
"$" is used as a line number and means the last line in the file.
"d" is usd to delete the respective line(last line in this case).
"*.txt" is used to select all files whose extension is .txt in the present directory.
You should use -i with sed statement
To modify and do some changes in file we need to specify -i in sed command
your command should be like
find . -type f -name '*.txt' -exec sed -i '$d' {} \;
But please note that it will update all the files with .txt and you wont be able to revert back so please take backup of important files
Considering the risk of loosing data while modifying large number of files using sed, this is what I used after creating a new sub-directory:
awk 'NR>1 {print last > "./modified/"FILENAME} {last=$0}' *.txt
This filters all the files with extension .txt into new files with changes to the sub-directory named modified.
Ref: what is the easiest way to remove 1st and last line from file with awk?

In Unix, how do I display the contents of all files that begin with a prefix?

a bunch of text files that start with the prefix r_ , and I want to display the contents of all these files at once.
I tried to use cat and a command like this :
cat [f_*] ,
But this doesn't work like I expect
Using that cat properly:
$ cat r_*
As there is some mixup in the OP about the starting letter, go ahead and use this: cat [fr]_* .
you can use tail or head commands,
tail -n +1 r_*
You can use a script something like this
path="<Your Path Here>"
find $path -name "r_*" | while read -r currentFile;
do
while read -r line;
do
HERE $line will be each line
done < $currentFile
done
Here find $path -name "r_*" will find all the files starting with a r_ in the given path and iterate each file one by one.
The loop while read -r line will read each line content for you to perform any action

How to rename file from the specific pattern within the file

I would like to change the file name according to the specific pattern within the file. Let's say I have the unique pattern that starts with "XmacTmas". I would like to use this pattern to rename the file with the additional character like "_dbp1".
Now my file name is "xxo1" and I want "XmacTmas_dbp1".
How can I do this in for thousands of files with some script.
Thanks
find . -name 'XmacTmas*' -exec echo mv {} {}_dbp1 \;
find the files of interest and execute command after replacing {} with the found filename.
Escape the ;. Without the \, find would take it as part of the command to execute.
If only files in the actual directory are needed, add -maxdepth 0 before -name (or any other of find's numerous options)
If the result is as needed, remove the echo

How to display contents of all files under a directory on the screen using unix commands

Using cat command as follows we can display content of multiple files on screen
cat file1 file2 file3
But in a directory if there are more than 20 files and I want content of all those files to be displayed on the screen without using the cat command as above by mentioning the names of all files.
How can I do this?
You can use the * character to match all the files in your current directory.
cat * will display the content of all the files.
If you want to display only files with .txt extension, you can use cat *.txt, or if you want to display all the files whose filenames start with "file" like your example, you can use cat file*
If it's just one level of subdirectory, use cat * */*
Otherwise,
find . -type f -exec cat {} \;
which means run the find command, to search the current directory (.) for all ordinary files (-type f). For each file found, run the application (-exec) cat, with the current file name as a parameter (the {} is a placeholder for the filename). The escaped semicolon is required to terminate the -exec clause.
I also found it useful to print filename before printing content of each file:
find ./ -type f | xargs tail -n +1
It will go through all subdirectories as well.
Have you tried this command?
grep . *
It's not suitable for large files but works for /sys or /proc, if this is what you meant to see.
You could use awk too. Lets consider we need to print the content of a all text files in a directory some-directory
awk '{print}' some-directory/*.txt
If you want to do more then just one command called for every file, you will be more flexible with for loop. For example if you would like to print filename and it contents
for file in parent_dir/*.file_extension; do echo $file; cat $file; echo; done

batch rename to change only single character

How to rename all the files in one directory to new name using the command mv. Directory have 1000s of files and requirement is to change the last character of each file name to some specific char. Example: files are
abc.txt
asdf.txt
zxc.txt
...
ab_.txt
asd.txt
it should change to
ab_.txt
asd_.txt
zx_.txt
...
ab_.txt
as_.txt
You have to watch out for name collisions but this should work okay:
for i in *.txt ; do
j=$(echo "$i" | sed 's/..txt$/_.txt/')
echo mv \"$i\" \"$j\"
#mv "$i" "$j"
done
after you uncomment the mv (I left it commented so you could see what it does safely). The quotes are for handling files with spaces (evil, vile things in my opinion :-).
If all files end in ".txt", you can use mmv (Multiple Move) for that:
mmv "*[a-z].txt" "#1_.txt"
Plus: mmv will tell you when this generates a collision (in your example: abc.txt becomes ab_.txt which already exists) before any file is renamed.
Note that you must quote the file names, else the shell will expand the list before mmv sees it (but mmv will usually catch this mistake, too).
If your files all have a .txt suffix, I suggest the following script:
for i in *.txt
do
r=`basename $i .txt | sed 's/.$//'`
mv $i ${r}_.txt
done
Is it a definite requirement that you use the mv command?
The perl rename utility was written for this sort of thing. It's standard for debian-based linux distributions, but according to this page it can be added really easily to any other.
If it's already there (or if you install it) you can do:
rename -v 's/.\.txt$/_\.txt/' *.txt
The page included above has some basic info on regex and things if it's needed.
Find should be more efficient than for file in *.txt, which expands all of your 1000 files into a long list of command line parameters. Example (updated to use bash replacement approach):
find . \( -type d ! -name . -prune \) -o \( -name "*.txt" \) | while read file
do
mv $file ${file%%?.txt}_.txt
done
I'm not sure if this will work with thousands of files, but in bash:
for i in *.txt; do
j=`echo $i |sed 's/.\.txt/_.txt/'`
mv $i $j
done
You can use bash's ${parameter%%word} operator thusly:
for FILE in *.txt; do
mv $FILE ${FILE%%?.txt}_.txt
done

Resources