This is the scenario,
For example, we have a list of files named as a.txt,b.txt,...z.txt. Goal is to name them as txt.a,txt.b,txt.c.....txt.z
Input:
a.txt
b.txt
c.txt
...
...
z.txt
Output:
txt.a
txt.b
txt.c
...
...
txt.z
I tried this one-liner and got the desired output. One-liner
ls -l *.txt | awk -F " " '{print $9}' | awk -F "." '{str1 = $2; str2 = "."; str3 = $1; str4 = str1 str2 str3; print str4}'
Ask: Could someone help if there is still any better way in bash to achieve this functionality?
CodePudding user response:
If the filename is the last column, and the files have a single dot, you can use a single awk to split on a dot and print the 2 parts in reverse.
Using $NF matches the last field.
ls -l *.txt | awk '
{
split($NF, a, ".")
print a[2] "." a[1]
}'
If there should be 2 parts after the split, you can check the result from split:
ls -l *.txt | awk '
{
n=split($NF, a, ".")
if (n == 2) print a[2] "." a[1]
}'
Or as an alternative using sed and 2 capture groups printed in reverse, using ls -1 to list one file per line.
ls -1 *.txt | sed -E 's/^([^.] )\.([^.]*)$/\2\.\1/'
CodePudding user response:
Assumptions/understanding:
- the objective is to rename the files (the question mentions
Goal is to name them as ...but there is no mention of themvcommand ... ???) - all file names contain a single period
- we want to switch the before-period/after-period portions of the file names to create new file names
- no files exist with the new file name (eg, we don't currently have files named
a.txtandtxt.a)
One idea using parameter expansion which allows us to eliminate the overhead of sub-process calls:
for fname in *.txt
do
new_fname="${fname#*.}.${fname%.*}"
echo mv "${fname}" "${new_fname}"
done
For files names a.txt, b.txt and c.txt this generates:
mv a.txt txt.a
mv b.txt txt.b
mv c.txt txt.c
Once OP is satisfied with the results the echo can be removed and the script should perform the actual mv/rename.
