I have folders as below. I want to create subdirectory with same name and move only few of the files into sub directory
Input
Parent
folder1/a.txt
folder1/b.txt
folder2/a.txt
folder2/b.txt
folder3/a.txt
folder3/b.txt
Output
Parent
folder1/folder1/a.txt
folder1/b.txt
folder2/folder2/a.txt
folder2/b.txt
folder3/folder3/a.txt
folder3/b.txt
I tried this , but this is working only for files not folders
for file in *; do dir=$(echo $file | cut -d. -f1); mkdir -p $dir; mv $file $dir; done
If your shell is bash, you can run the following:
for file in */a.txt ; do
dir=${file%/a.txt}
mkdir "$dir/$dir"
mv "$file" "$dir/$dir"
done
It uses the parameter expansion to remove the /a.txt from the file name which only leaves the directory name in $dir.
Related
There is a child directory who name is stored in a variable called temp.
I'd like to rename all files in that directory to their lower case version.
So I wrote this code:
mv ls $temp 'ls $temp | tr [:upper:][:lower:] [:lower:][:upper:]'
but it doesn't work. How can I change it?
You need a loop.
You can use Bash brace expansion to convert to lower case, instead of tr which creates an extra process each time:
#!/bin/bash
cd "$temp"
for f in *; do
mv "$f" "${f,,}"
done
If you want to reverse the case of each character of the file name (thanks #SLePort for the tip):
#!/bin/bash
cd "$temp"
for f in *; do
mv "$f" "${f~~}"
done
I have multiple sub folders e.g.:
ls ./
F1 F2 F5 F8 F12 ...
Each folder contain file "file.txt"
How to copy all file.txt files to main folder containing folder name?
cp ./F1/file.txt ./file_1.txt
cp ./F2/file.txt ./file_2.txt
...
Perl One Liner
first go to main folder than:
find . | perl -a -F/ -lne 'qx(cp -r "$F[1]" T/ )'
note
do not worry about log file on the screen if would be!
T/
is your target directory
main folder
Where all your file exist. If your all file is in the folder Music for example; so cd Music then that Perl One Liner
declare -a dirs
i=1
for d in */
do
dirs[i++]="${d%/}"
done
echo "There are ${#dirs[#]} dirs in the current path"
for((i=1;i<=${#dirs[#]};i++))
do
echo "Copying file.txt from ${dirs[i]} dir..."
cp ./${dirs[i]}/file.txt ./file_$i.txt
done
Save it as a script file, fileTxtCopy.sh, for instance. Then place it at the parent dir and give it executable permission sudo chmod +x fileTxtCopy.sh.
Run it as script and you should have all your file.txt file copied in parent dir.
Copies file.txt files from each folder inside a current directory to the current directory and appends numbers contained in a folder name to the name of the copied file.
for i in *; do a=$(<<< "$i" grep -o "[0-9]*" -); cp "$i/file.txt" "file_$a.txt"; done
Not the most robust approach though.
I have files like this
This list is a sample of my files note the actual files are not in sucessive order.
file1.a
file2.a
file1.b
file2.b
...
and some have a .c extension but not all
How would I move these files into their own named folder.
I have tried this
find . -type f -print0 | xargs -0 -l sh -c 'mkdir "${1%.*}" && mv "$1" "${1%.*}"' sh
but it doesn't work as intended i.e. Well it creates the folders but wont put the second file of same name different extension in the same folder.
mkdir: cannot create directory ‘./file1’: File exists
mkdir: cannot create directory ‘./file2’: File exists
mkdir: cannot create directory ‘./file3’: File exists
You should use mkdir -p, it won't complain (and break the &&) if directories exist (it will also create parent directories if those don't exist).
for FILE in $(ls file[0-9].[a-z])
do
DIRNAME=$(echo $FILE |cut -c1-5)
[ -d $DIRNAME ] || mkdir $DIRNAME
mv ${FILE}* $DIRNAME
done
This will give you:
$ ls file1 file2
file1:
file1.a file1.b file1.c
file2:
file2.a file2.b file2.c
I have several hundred rar files. I would like to create a directory for each rar file then move the file into the newly created directory.
This is the code I am using to create the rar's
#!bin/bash
for f in *; do
rar a -s -m5 "${f%.*}.rar" "$f";
done
This is the code I am using to move the files.
#!/bin/bash
for i in *.rar; do
dir=$(echo "$i" | \
sed 's/\(.\)\([^ ]\+\) \([^ ]\+\) - \(.*\)\.pdf/\1\/\1\2 \3/')
dir="DestinationDirectory/$dir"
mkdir -p -- "$dir" && mv -uv "$i" "$dir/$i"
done
The problem is that it creates the directory with the extension name.
ie: file irclog3_26_198.rar is moved into folder /DestinationDirectory/irclog3_26_1988.rar/irclog3_26_1988.rar
I would like the folder to be created ignoring the .rar and just use the name of the file.
How about:
dir="${dir%.rar}"
mkdir -p -- "$dir" ...
Read more about it at the abs.
dir=$(echo ${i[#]::-4})
${name[#]:pos:len}) gets the substring/subarray of the string/array, for string, [#] can be avoid.
dir=$(echo ${i::-4})
You can use the normal bash shell parameter expension https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
FILE="TEST.rar"
echo "${FILE%%.*}"
--> TEST
I am working on something and need to solve the following. I am giving a analogous version of mine problem.
Say we have a music directory, in which there are 200 directories corresponding to different movies. In each movie directory there are some music files.
Now, say a file music.mp3 is in folder movie.mp3 . I want to make a shell script such that it renames the file to movie_music.mp3 and put it in some folder that I mention to it. Basically, all the files in the subdirectories are to be renamed and to be put in a new directory.
Any workaround for this?
This script receives two arguments: the source folder and the destination folder. It will move every file under any directory under the source directory to the new directory with the new filename:
#!/bin.sh
echo "Moving from $1 to $2"
for dir in "$1"/*; do
if [ -d "$dir" ]; then
for file in "$dir"/*; do
if [ -f "$file" ]; then
echo "${file} -> $2/`basename "$dir"`_`basename "${file}"`"
mv "${file}" "$2"/`basename "$dir"`_`basename "${file}"`
fi
done
fi
done
Here is a sample:
bash move.sh dir dir2
Moving from dir to dir2
dir/d1/f1 -> dir2/d1_f1
dir/d1/f2 -> dir2/d1_f2
dir/d2/f1 -> dir2/d2_f1
dir/d2/f2 -> dir2/d2_f2
Bash:
newdir=path/to/new_directory;
find . -type d |while read d; do
find "$d" -type f -maxdepth 1 |while read f; do
movie="$(basename "$d" |sed 's/\(\..*\)\?//')"
mv "$f" "$newdir/$movie_$(basename $f)";
done;
done
Assuming the following directory tree:
./movie1:
movie1.mp3
./movie2:
movie2.mp3
The following one-liner will create 'mv' commands you can use:
find ./ | grep "movie.*/" | awk '{print "mv "$1" "$1}' | sed 's/\(.*\)\//\1_/'
EDIT:
If your directory structure contains only the relevant directories, you can expand use the following grep instead:
grep "\/.*\/.*"
Notice it looks file anything with at least one directory and one file. If you have multiple inner directories, it won't be good enough.