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 themv
command ... ???) - 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.txt
andtxt.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.