How to create files with folder names recursively using script? - linux

I have a folder structure that can have x subfolders, like so:
Folder 1
Sub-folder 1
Sub-folder 2
Sub-sub-folder 3
Folder 2
I want to create an empty file that has the name of the sub-folders (with .file appended) in their parent folders, as presented here:
Folder 1
Sub-folder 1.file (newly created file that has the same name as the sister folder)
Sub-folder 1
Sub-folder 2.file (newly created file that has the same name as the sister folder)
Sub-folder 2
Sub-sub-folder 3.file (newly created file that has the same name as the sister folder)
Sub-sub-folder 3
Folder 2
Some folders might have spaces in their names, so I've tried the following but it's not working even though echoing $(dirname $dir)/$dir seems to yield the expected result:
#!/bin/bash
find . -mindepth 1 -type d | while read dir
do
touch $(dirname $dir)/$dir.file
done
What would be the best way to achieve this?
Thank you so much in advance!
post updated to try to be clearer

perhaps you could try:
find . -type d | while IFS= read -r d
do
( cd "$d" && cd .. && touch "$(basename "$d").file" )
done

I have tried with awk, check this if its useful for you.
I am giving .file for file name
realpath Fol*/* | awk '{print "touch "$1".file"}' | sh

Related

Linux - How to zip files per subdirectory separately

I have directory structure like this.
From this I want to create different zip files such as
data-A-A_1-A_11.zip
data-A-A_1-A_12.zip
data-B-B_1-B_11.zip
data-C-C_1-C_11.zip
while read line;
do
echo "zip -r ${line//\//-}.zip $line";
# zip -r "${line//\//-}.zip" "$line"
done <<< "$(find data -maxdepth 3 -mindepth 2 -type d)"
Redirect the result of a find command into a while loop. The find command searches the directory data for directories only, searching 3 directories deep only. In the while loop with use bash expansion to convert all forward slashes to "-" and add ".zip" in such a way that we can build a zip command on each directory. Once you are happy that the zip command looks fine when echoed for each directory, comment in the actual zip command

How can I make a bash script where I can move certain files to certain folders which are named based on a string in the files?

This is the script that I'm using to move files with the string "john" in them (124334_john_rtx.mp4 , 3464r64_john_gty.mp4 etc) to a certain folder
find /home/peter/Videos -maxdepth 1 -type f -iname '*john' -print0 | \
xargs -0 --no-run-if-empty echo mv --target-directory=/home/peter/Videos/john/
Since I have a large amount of videos with various names written in the files, I want to make a bash script which moves videos with a string between the underscores to a folder named based on the string between the underscores. So for example if a file is named 4345655_ben_rts.mp4 the script would identify the string "ben" between the underscores, create a folder named as the string between the underscores which in this case is "ben" and move the file to that folder. Any advice is greatly appreciated !
My way to do it :
cd /home/peter/Videos # Change directory to your start directory
for name in $(ls *.mp4 | cut -d'_' -f2 | sort -u) # loops on a list of names after the first underscore
do
mkdir -p /home/peter/Videos/${name} # create the target directory if it doesn't exist
mv *_${name}_*.mp4 /home/peter/Videos/${name} # Moving the files
done
This bash loop should do what you need:
find dir -maxdepth 1 -type f -iname '*mp4' -print0 | while IFS= read -r -d '' file
do
if [[ $file =~ _([^_]+)_ ]]; then
TARGET_DIR="/PARENTPATH/${BASH_REMATCH[1]}"
mkdir -p "$TARGET_DIR"
mv "$file" "$TARGET_DIR"
fi
done
It'll only move the files if it finds a directory token.
I used _([^_]+)_ to make sure there is no _ in the dir name, but you didn't specify what you want if there are more than two _ in the file name. _(.+)_ will work if foo_bar_baz_buz.mp4 is meant to go into directory bar_baz.
And this answer to a different question explains the find | while logic: https://stackoverflow.com/a/64826172/3216427 .
EDIT: As per a question in the comments, I added mkdir -p to create the target directory. The -p means recursively create any part of the path that doesn't already exist, and will not error out if the full directory already exists.

How to use the depth level 2 or maxdepth as output text file for my bash script below

I'm now using the bash script below to create file listing in each level 2 depth directories and output as text file in each particular folders.
But, i can only name it as "File.txt"
How to use the level 2 depth directory as the output text file name
e.g. while list the files in /users/bin/ the output file should named "bin.txt"
here's the code that i'm using.
#!/bin/bash
while IFS= read -r -d '' folder; do
echo $folder find "$folder" -type f > "$folder"/File.txt
done < <(find . -maxdepth 2 -mindepth 2 -type d -print0)
You have to account for (1) files in the present working directory (which will have no path component aside from '.'), and (2) the rest of the files in the level 2 directories. If for instance, you wanted to output your list of the files in the present directory to pwd.txt and each file in the level 2 directories to files with the respective directory names (e.g. ./dir1/file_a.txt into dir1.txt), you could do something similar to the following in the body of your loop:
tmp="${folder%/*}" ## remove filename
lvl2name="${tmp##*/}" ## remove leading path components
[[ $lvl2name = '.' ]] && lvl2name="pwd" ## handle files in pwd to pwd.txt
echo $folder find "$folder" -type f >> "$lvl2name.txt"
It is up to you to truncate any existing "$lvl2name.txt" files before each subsequent run of the script. You could make a previous call to find . -maxdepth 2 -type d ... before your enter you file loop to get the directory names or something similar.
Give it a try and let me know if you have questions.

Moving folders with the same name to new directory Linux, Ubuntu

I have a folder with 100,000 sub-folders.
Because of the size I cannot open the folder.
Now I am looking for a shell script to help me move or split the folders.
Current = Folder Research : with 100,000 sub-folders. (Sorted A, B, C, D)
Needed = New folder All folders starting with name A-science. should be moved to a new
folder AScience.
All folders starting with B-Science.. should be move to a new folder BScience
I found this script below. But don't know how to make it work.
find /home/spenx/src -name "a1a2*txt" | xargs -n 1 dirname | xargs -I list mv list /home/spenx/dst/
find ~ -type d -name "*99966*" -print
I had a look at the command you supplied to see what it did. here's what each command does (correct me if I'm wrong)
| = pipes output of command to the left of pipe to the input of the command on the right
find /home/spenx/src -name "a1a2*txt" = finds all files within given directory that match between "" and pipes output
xargs -n 1 dirname = takes in all the piped files outputted by the find command and gets the directory name of each file and pipes to output
xargs - I list mv list /home/spenx/dst = takes in all piped folders and and puts them into list variable, mv all items in list to the given folder
find ~ -type d -name "**" -print = runs a test for all files within given name to see if they exist and print any found out (this line is only a test command, it's not necessary for the actual move)
/home/spenx/src = folder to look in (absolute file path, or just folder name without '/')
/home/spenx/dst = folder to move all files to (absolute file path, or just folder name without '/')
"a1a2*txt" = files to look for (since you only care about folders, just use *.* to catch all files
"*99966* = files to test for but I'm not sure what you would put here
I took a look at the command and decided to modify it a little, but It still won't move each folder category (i.e. A-science, B-science) into a separate dirs, this will just get all folders in a given directory and move them to a given destination, or at least as far as I can tell.
You might want to try find all folders of each category ( A-Science) and moving them to a destination folder of Ascience one by one like so
find /home/spenx/src -name "A-science/*.*" | xargs -n 1 dirname | sort -u | xargs - I list mv list /home/spenx/dst/Ascience
find /home/spenx/src -name "B-science/*.*" | xargs -n 1 dirname | sort -u | xargs - I list mv list /home/spenx/dst/Bscience
Again, test the command out before using it on your actual files.
You might want to take look at this question, specifically:
list.txt
1abc
2def
3xyz
script to run:
while read pattern; do
mv "${pattern}"* ../folder_b/"$pattern"
done < list.txt

How can I generate a folder with the last X files added?

So I have a huge folder full subfolders with tons of files, and I add files to it all the time.
I need a subfolder in the root of that folder with a symlink of the last 10-20 files added so that I can quickly find the things I recently added. This is located on a NAS, but I have a linux box running Arch connected through NFS, so I assume the best way is to run a bash script with a find command followed by a loop of ln -sf, but I can't do it safely without help.
Something like this is required:
mkdir -p subfolder
find /dir/ -type f -printf '%T# %p\n' | sort -n | tail -n 10 | cut -d' ' -f2- | while IFS= read -r file ; do ln -s "$file" subfolder ; done
Which will create symlinks in subfolder pointing to the 10 most recently modified files in the directory tree rooted at /dir/
You could just create a shell function like:
recent() { ls -lt ${1+"$#"} | head -n 20; }
which will give you a listing of the 20 most recent items in the specified directories, or the current directory if no arguments are given.

Resources