ksh rename multiple files with prefix entered by user to another prefix entered by user - rename

pretty new to scripting...
Lets say I have multiple files with multiple prefixes in current directory. I need to rename them based on user input.
Let's say I have aaa_file.dat and bbb_file.dat aaa_log.dat ccc.txt and so on.
Script will ask to enter "old prefix" and enter "new prefix" and search files with "old" prefix and mv it into name with "new" prefix.
print "enter old prefix" ;
read old ;
print "enter new prefix" ;
read new ;
find and rename part is where I get stuck..
for $old in * ;
do mv $old_* $new_* ;
done
If I enter as user aaa and the zzz my files, my result should be:
aaa_file.dat and aaa_log.dat are now named zzz_file.dat zzz_log.dat

You have some mistakes in
for $old in * ;
do
mv $old_* $new_* ;
done
When you use a for-loop, a value will be assigned to the loop variable. So drop the $ in for $old in *.
You already have assigned a value to the variable old, you do not want to overwrite it with a new value. Use a new variable like for file in * (or for file in ${old}*).
Variables can have understores in their name. $old_* is not the same as ${old}_*. Get used to using those braces in all cases except for one character variables when they are followed by a space or quote.
You are hoping for some magic, when you write ${new}_*. The variable will be extended to its value (like zzz), the shell searches for files starting with zzz_ (non found) and will try (when you hae written mv ${old}_* ${new}_*) to move all files with their name starting with aaa_ to a directory called zzz_*.
So construct a new filename from the old one with something like sed:
The new filename must be constructed from the old filename.
for file in ${old}_*; do
newfile=$(echo "${file}"| sed "s/^${old}_/${new}_/")
# Remove the word echo when the command shows the mv commands you like
echo mv "${file}" "${newfile}"
done

Related

Append all the files located in path made of wild card characters

I'm trying to add "aaa" to the "ami" files without specifying full path
I tried this:
echo "aaa" >> /home/thomas/*-bbb-*/ami
instead of typing each path separate such as /home/thomas/1-bbb-2/ami and /home/thomas/1-bbb-3/ami and so on
Or should I somehow search recursively for all the files named "ami" in /home/thomas/ and add them to a variable and then append all those files in that variable?
Try using loop:
for i in `seq 150` #change 150 to your value
do
echo "aaa" > /home/thomas/1-bbb-$i/ami
done
This will work if your paths change in one place (like your example).
Save the file names in an array.
files=(/home/thomas/[0-9]*-bbb-[0-9]*/ami)
for f in "${files[#]}"; do echo 'aaa' >> "$f"; done

How to add sequential numbers say 1,2,3 etc. to each file name and also for each line of the file content in a directory?

I want to add sequential number for each file and its contents in a directory. The sequential number should be prefixed with the filename and for each line of its contents should have the same number prefixed. In this manner, the sequential numbers should be generated for all the files(for names and its contents) in the sub-folders of the directory.
I have tried using maxdepth, rename, print function as a part. but it throws error saying that "-maxdepth" - not a valid option.
I have already a part of code(to print the names and contents of text files in a directory) and this logic should be appended with it.
#!bin/bash
cd home/TESTING
for file in home/TESTING;
do
find home/TESTING/ -type f -name *.txt -exec basename {} ';' -exec cat {} \;
done
P.s - print, rename, maxdepth are not working
If the name of the first file is File1.txt and its contents is mentioned as "Louis" then the output for the filename should be 1File1.txt and the content should be as "1Louis".The same should be replaced with 2 for second file. In this manner, it has to traverse through all the subfolders in the directory and print accordingly. I have already a part of code and this logic should be appended with it.
There should be fail safe if you execute cd in a script. You can execute command in wrong directory if you don't.
In your attempt, the output would be the same even without the for cycle, as for file in home/TESTING only pass home/TESTING as argument to for so it only run once. In case of
for file in home/TESTING/* this would happen else how.
I used find without --maxdepth, so it will look into all subdirectory as well for *.txt files. If you want only the current directory $(find /home/TESTING/* -type f -name "*.txt") could be replaced to $(ls *.txt) as long you do not have directory that end to .txt there will be no problem.
#!/bin/bash
# try cd to directory, do things upon success.
if cd /home/TESTING ;then
# set sequence number
let "x = 1"
# pass every file to for that find matching, sub directories will be also as there is no maxdeapth.
for file in $(find /home/TESTING/* -type f -name "*.txt") ; do
# print sequence number, and base file name, processed by variable substitution.
# basename can be used as well but this is bash built in.
echo "${x}${file##*/}"
# print file content, and put sequence number before each line with stream editor.
sed 's#^#'"${x}"'#g' ${file}
# increase sequence number with one.
let "x++"
done
# unset sequence number
unset 'x'
else
# print error on stderr
echo 'cd to /home/TESTING directory is failed' >&2
fi
Variable Substitution:
There is more i only picked this 4 for now as they similar.
${var#pattern} - Use value of var after removing text that match pattern from the left
${var##pattern} - Same as above but remove the longest matching piece instead the shortest
${var%pattern} - Use value of var after removing text that match pattern from the right
${var%%pattern} - Same as above but remove the longest matching piece instead the shortest
So ${file##*/} will take the variable of $file and drop every caracter * before the last ## slash /. The $file variable value not get modified by this, so it still contain the path and filename.
sed 's#^#'"${x}"'#g' ${file} sed is a stream editor, there is whole books about its usage, for this particular one. It usually placed into single quote, so 's#^#1#g' will add 1 the beginning of every line in a file.s is substitution, ^ is the beginning of the file, 1 is a text, g is global if you not put there the g only first mach will be affected.
# is separator it can be else as well, like / for example. I brake single quote to let variable be used and reopened the single quote.
If you like to replace a text, .txt to .php, you can use sed 's#\.txt#\.php#g' file , . have special meaning, it can replace any singe character, so it need to be escaped \, to use it as a text. else not only file.txt will be matched but file1txt as well.
It can be piped , you not need to specify file name in that case, else you have to provide at least one filename in our case it was the ${file} variable that contain the filename. As i mentioned variable substitution is not modify variable value so its still contain the filename with path.

rename all files after extension

Is it possible to write a script to rename all files after the extension?
Example in the folder, there are :
hello.txt-123ahr
bye.txt-56athe
test.txt-98hg12
I want the output:
hello.txt
bye.txt
test.txt
If you just want to remove everything from the dash forwards, you can use Parameter expansion:
#!/bin/bash
for file in *.txt-* ; do
mv "$file" "${file%-*}"
done
Where ${file%-*} means "remove from $file everytning from the last dash". If you want to start from the first dash, use %%.
Note that you might overwrite some files if their leading parts are equivalent, e.g. hello.txt-123abc and hello.txt-456xyz.

How to create directories automatically in linux?

I am having a file named temp.txt where inside this file it contains the following content
https://abcdef/12345-xyz
https://ghifdfg/5426525-abc
I need to create a directories automatically in linux by using only th number part from each line in the file.
So the output should be something like 12345 and 5426525 directories created.
Any approach on how to do this could be helpful.
This is the code that i searched and got from internet,wherein this code, new directories will be created by the file name that starts with BR and W0 .
for file in {BR,W0}*.*; do
dir=${file%%.*}
mkdir -p "$dir"
mv "$file" "$dir"
done
Assuming each URL is of the form
http[s]://any/symbols/some_digits-some_letters
Then you indeed could use the simple prefix and suffix modifiers in shell variable expansion.
${x##*/} expands to the suffix part of x that starts after the last slash /.
${y%%-*} expands to the prefix part of y before the first -.
while read x ; do
y=${x##*/}
z=${y%%-*}
mkdir $z
done < temp.txt

Replacing a string with a given text using Linux shell script

I have a file named testfile.It contains some information like
methun:x:500:500:comment:/home/methun:bin/bash
salahuddin:x:501:500:comment:/home/methun:bin/bash
Now implemented a following shell program:
echo "Enter a Name:"
read username
users='cat /mypractice/myfiles/testfile | awk -F ':' '{print $1}''
for user in $users
do
if [ "$user" == "$username" ]; then
echo "Name found and Enter a new name to change."
read newUsername
#need code to change text on my file --->testfile
fi
done
Now suppose I need to change methun to Moin. Comment to newcomment. I used
sed -i 's/"$user"/"$newuser"/g' /mypractice/myfiles/testfile
But it not working here. I test with it in my testfile singly it change and replace all.But i need to change only that position i want .
I also tried with usermod but it will not works here..
Can anyone give me the solution or correct my code...Thanks
You are using g flag in your sed command which means global substitution (will change all occurrences). Also, the variables although quoted are wrapped inside single quotes and hence are not interpolated.
Try this:
sed -i "s/^$user/$newuser/" /mypractice/myfiles/testfile
I have placed a ^ anchor in the substitution part which means only substitute if the word is at the beginning of the line. This protects you from making a change if the name of the user is not at the start but somewhere in the middle.

Resources