I'm trying to create a directory with list of directories with list of files.
Could you explain me, why this script doesn't work properly?
createapp() {
local folders=('graphql' 'migrations' 'models' 'tests')
local files=('__init__.py' 'admin.py' 'apps.py' 'views.py')
cd backend/apps
mkdir $COMMAND2
cd $COMMAND2
for folder in $folders
do mkdir $folder && cd $folder
for file in $files
do touch $file && cd ..
done
done
}
It creates a graphql directory, and an __init__.py file in it, but that's all.
There are a few problems:
You aren't iterating over the contents of the array, only the first element.
You are executing cd .. too soon; you want to do that after the loop that creates each file.
for folder in "${folders[#]}"; do
mkdir -p "$folder" &&
cd "$folder" &&
for file in "${files[#]}"; do
touch "$file"
done &&
cd ..
done
There are two ways to simplify this. If you keep the cd command, you only need one call to touch:
for folder in "${folders[#]}"; do
mkdir -p "$folder" && cd "$folder" && touch "${files[#]}" && cd ..
done
Or you can get rid of the cd command, and pass a longer path to touch:
for folder in "${folders[#]}"; do
mkdir -p "$folder" &&
for file in "${files[#]}"; do
touch "$folder/$file"
done
done
or even
for folder in "${folders[#]}"; do
mkdir -p "$folder" &&
touch "${files[#]/#/$folder/}"
done
If you want to get fancy, you can do all of this with zero loops and a combination of bash brace and array expansions:
#!/bin/bash
createapp() {
local folders=('graphql' 'migrations' 'models' 'tests')
local files=('__init__.py' 'admin.py' 'apps.py' 'views.py')
IFS=,
eval mkdir -p "{${folders[*]}}"
eval touch "{${folders[*]}}/{${files[*]}}"
}
Note that the use of eval can be dangerous, but it's pretty limited in this implementation as the two arrays are local and not using user-defined input. If this was zsh, you could embed brace and array expansion without the need for eval
Related
I am trying to make a photo organizer with a zsh shell script. But i am having trouble creating sub directories within each main directory(based on date). Currently the script starts from a folder i created and gets one argument(the file it needs to edit, hence the first cd $1). Secondly, i do some name changing which is irrelevant for my question. Next i create a directory for each date and move the photo to the correct directory.
The issue is, i want to loop through each date folder and make 2 new sub directories(jpg and raw). But when i run the code i get an error that there is no such file or directory..
Here is my current script:
#!/bin/zsh.
cd $1
for i in *.JPG;
do
mv $i $(basename $i .JPG).jpg;
done
for i in *;
do
d=$(date -r "$i" +%d-%m-%Y)
mkdir -p "$d"
mv -- "$i" "$d/";
done
for d in *;
do
cd $d
for i in *.jpg;
do
mkdir -p "jpg"
mv -- "$i" "jpg";
done
for i in *.NEF;
do
mkdir -p "raw"
mv -- "$i" "raw";
done
done
If anyone knows where i made a mistake that would be really helpfull since i have no clue what goes wrong and there is no debugger in nano as far as i know.
I would like to do the following:
Backup the current folder
Run some test files
Restore the backup (delete all changes from previous commands)
Delete backup
Unfortunately I do not have Git available. Otherwise I would do
git add .
git commit -m "backup"
# run commands
git checkout .
The simplest possible way would be to just create a copy in the parent directory or other convenient location.
You could create such aliases to make it easier:
alias bak-cur-dir='(DIR="${PWD##*/}" && cd .. && cp -r "$DIR" "$DIR".bak)'
alias res-cur-dir='(DIR="${PWD##*/}" && cd .. && rm -rf "$DIR" && mv "$DIR".bak "$DIR") && cd .. && cd -'
I use in such a case to create a directory ${TMP:-/tmp}/$$ for this purpose. You can later change the location, just by defining TMP, and it uses something reasonable, when TMP is unset.
tmpdir=${TMP:-/tmp}/$$
mkdir -p "$tmpdir"
cp -r . "$tmpdir"
.... # Do your processing and set
.... # the variable keep_backup to
.... # your liking.
# Remove unneeded backup, when done.
if ((keep_backup == 0))
then
rm -r "$tmpdir"
else
echo You find a backup in $tmpdir
fi
cd /working/dir
tar cfz ../backup.tar.gz .
# do your thing
#
# and then some
rm *
tar xf ../backup.tar.gz
rm ../backup.tar.gz
I have a set of banners that include .jpg and .psd. I need to create folder for them and move them into it.
example:
Banner-A.jpg
Banner-A.psd
Banner-B.jpg
Banner-B.psd
Banner-C.jpg
Banner-C.psd
Create folder and move them:
Banner-A/Banner-A.jpg Banner-A.psd
Banner-B/Banner-B.jpg Banner-B.psd
Banner-C/Banner-C.jpg Banner-C.psd
I manage to find a script here that work for the first part but I can't get the .psd to move as well.
for f in "$#"; do
cd "$f"
for file in *.jpg; do
folder=$(basename "$file" ".jpg")
mkdir -p "$folder" && mv "$file" "$folder"
done
done
Change your mv command to use the * wildcard as follows:
for file in *.jpg; do
folder=$(basename "$file" ".jpg")
mkdir -p "${folder}" && mv "${folder}".* "${folder}"
done
Make sure the .* is outside the quotes and it should work.
Example script:
#!/bin/bash
set -uo pipefail
doWork() {
dir="${1}"
cd "${dir}" || return
for file in *.jpg; do
folder=$(basename "$file" ".jpg")
mkdir -p "${folder}" && mv "${folder}".* "${folder}"
done
}
doWork "$#"
Example data directory: (before executing script)
$ ls data
Banner-A.jpg Banner-A.psd Banner-B.jpg Banner-B.psd Banner-C.jpg Banner-C.psd
Run script:
./script.sh ./data
data directory after script:
$ ls data
Banner-A Banner-B Banner-C
data directory subdirectories:
$ ls data/Banner-*
data/Banner-A:
Banner-A.jpg Banner-A.psd
data/Banner-B:
Banner-B.jpg Banner-B.psd
data/Banner-C:
Banner-C.jpg Banner-C.psd
I'd probably just use
for f in Banner*.jpg Banner*.psd; do
mkdir -p "${f%.???}/"
mv "$f" "${f%.???}/"
done
It will execute the mkdir -p for the *.psg files after the *.jpg has already created the folder, but covers the odd cases where there might be one of the files but not the other.
I'm working on a bash script that should do the following: for every directory beginning with Event_*, (in cat eventList), cd into the directory, and if the string "ZJ.ROT" exists in the file *.mcp, I want to copy the file "ROT" to another directory. In simpler terms: loop through directories: if string "ZJ.ROT" exists in a file in that directory, output another file from that directory to a separate directory.
#!/bin/bash
mkdir newdire
for dir in `cat eventList`; do
cd $dir
pwd
if grep "ZJ.KNYN" *.mcp; then
cp "ROT" "newdire"
fi
done
The error I get is:
./azim.sh: line 5: cd: Event_2014.11.21.10.10.19.630: No such file or directory
/Users/files/Event_2013.12.01.06.29.57.800
grep: *.mcp: No such file or directory
For some reason, this for loop isn't looping through each directory, but it's stuck in the first directory Event_2013.... Any ideas about how to implement this code?
After the first time you cd to a subdirectory you are in it for all future loop iterations so your subsequent cds will fail, as you are experiencing. You also need to quote your variables and there's other issues. Try this:
pwd="$PWD"
mkdir newdire
while IFS= read -r dir; do
cd "$dir"
grep -Fq "ZJ.KNYN" *.mcp &&
cp "ROT" "${pwd}/newdire"
cd "$pwd"
done < eventList
but of course you don't actually need to cd:
mkdir newdire
while IFS= read -r dir; do
grep -Fq "ZJ.KNYN" "$dir"/*.mcp &&
cp "${dir}/ROT" newdire
done < eventList
Problem seems to be here:
if grep "ZJ.KNYN" *.mcp; then
You should use -q option in grep to suppress the output and check the return status like this:
if grep -qF "ZJ.KNYN" *.mcp; then
-F is for fixed string search.
Also there is no need to change directory inside the loop.
Your full script can be better rewritten as:
#!/bin/bash
mkdir newdire
for dir in Event_*; do
if [[ -d "$dir" ]] && grep -qF "ZJ.KNYN" "$dir"/*.mcp 2>/dev/null; then
cp "$dir/ROT" "newdire/"
fi
done
I have a directory structure like and I am looping through directories like but getting error that could not find the directory any idea? In the first dir it is looking for dir1 dir2 dir3 and so on and in the second dir1 it is looking for dirA dir B and dirC Thanks.
./subtle1/
/fooA/file.txt
/fooB/file.txt
/fooC/file.txt
./subtle2/
/fooA/file.txt
/fooB/file.txt
/fooC/file.txt
for i in ~/new/subtle*;
do
if [ -d "$i" ] ;
then
cd $i
for j in "$i"/foo* ; do
if [ -d "$j" ] ;
then
cd $j
mv file.txt $i.$j.file.txt
done
done
One problem that strikes me immediately is that you cd within a loop, and you don't come out of that directory for the next iteration.
So you'll cd into ~/new/subtle1/fooA, do some work, and then for the next iteration you're already in that directory, whereas you want to be at your original (starting) point.
I would check out pushd/popd. pushd works like cd, but it maintains a stack of visited directories, and popd will take you back in that stack.
e.g.
$ pwd
/home/brian
$ pushd /var/log
$ pwd
/var/log
$ popd
$ pwd
/home/brian
If you want to just change the filenames that way:
mv ./subtle1/fooB/file.txt ./subtle1/fooB/subtle1.fooB.file.txt
mv ./subtle1/fooA/file.txt ./subtle1/fooA/subtle1.fooA.file.txt
mv ./subtle1/fooC/file.txt ./subtle1/fooC/subtle1.fooC.file.txt
mv ./subtle2/fooB/file.txt ./subtle2/fooB/subtle2.fooB.file.txt
mv ./subtle2/fooA/file.txt ./subtle2/fooA/subtle2.fooA.file.txt
mv ./subtle2/fooC/file.txt ./subtle2/fooC/subtle2.fooC.file.txt
than all you need is:
find -type f -print|sed -r -e 's/\.\/(.+)\/(.+)\/(.+)/\0 .\/\1\/\2\/\1.\2.\3/'|xargs -n 2 mv
If you really want to do this by a script and use cd to walk around than try this:
#!/bin/bash
for sub in subtle*; do
if [ -d "${sub}" ]; then
cd ${sub}
for foo in foo*; do
if [ -d "${foo}" ]; then
cd ${foo}
pwd
echo mv -- file.txt ${sub}.${foo}.file.txt
cd ..
fi
done
cd ..
fi
done
you can remove pwd and echo to just execute mv.