Zip I/O error: No such file or directory in bash script - bash

I've been writing some code to (mostly) automate password protecting and compressing/archiving folders and files. However, the code seems to hate me.
I've run it line by line, and it always chokes on the zip command, even when the $file and $source are correct and valid.
Any ideas?
Here's the source code:
#!/bin/bash
echo "Drag in the source file"
read source
echo
echo "Drag in the destination file, or press enter to select the Desktop"
read destination
echo
if [ -z "$destination" ]
then destination="$PWD/Desktop"
echo "Destination is set to the desktop"
fi
echo "Type the name of the file to make"
read file
if [ -z "$file" ]
then file="archive"
echo "File name set to archive.zip"
fi
file="${destination}/${file}"
if [ -d $"source" ]
then zip -erj "$file" "$destination"
else zip -ej "$file" "$destination"
fi

There are a couple of problems in your code:
if [ -z "$destination" ]
then destination="$PWD/Desktop"
echo "Destination is set to the desktop"
fi
$PWD is the current working directory. It is your home directory when you open a Terminal but it changes everytime you run cd.
The Desktop directory is $HOME/Desktop.
If you don't run the script from your home directory, most probably $PWD/Desktop doesn't exist and this is a cause for errors; zip doesn't attempt to create the destination directory for the archive you ask it to build. If the directory doesn't already exist it displays an error message and exits.
Another problem is on the invocation of zip:
if [ -d $"source" ]
then zip -erj "$file" "$destination"
else zip -ej "$file" "$destination"
fi
You probably want to archive the file $source or the files in the $source directory (if it is a directory) but you mistakenly put $destination as the file/directory to archive in the zip command line.
if [ -d $"source" ] -- it should be "$source", otherwise the quote are useless and if $source contains spaces the script will exit with a syntax error.
One last thing: zip doesn't mind receiving -r in the command line when it is asked to archive only one file. You can replace the entire if/else block above with a single command:
zip -erj "$file" "$source"

Related

Check if file exist relative to current script (one level up)

How to check/get file path relative to current script?
Script is running from ..../app/scripts/dev.sh
File to check from ..../app/dist/file.js
dir="${BASH_SOURCE%/*}../dist/backend.js"
if [ -f ${dir} ]; then
echo "file exists. ${dir}"
else
echo "file does not exist. ${dir}"
fi
There are three problems in your script.
To store the output of a command in a variable, use $(), not ${}.
[ -f "$dir" ] checks if $dir is a a file, which will never happen, because dirname outputs a directory.
Your script can be executed from any other working directory as well. Just because the script is stored in ···/app/scripts/ does not mean it will always run from there.
Try
file=$(dirname "$BASH_SOURCE")/../dist/file.js
if [ -f "$file" ]; then
echo "file exists."
else
echo "file does not exist."
fi

Is there a way I can take user input and make it into a file?

I am not able to find a way to make bash create a file with the same name as the file the user dragged into the terminal.
read -p 'file: ' file
if [ "$file" -eq "" ]; then
cd desktop
mkdir
fi
I am trying to make this part of the script take the name of the file they dragged in so for example /Users/admin/Desktop/test.app cd into it copy the "contents" file make another folder with the same name so test.app for this example and then paste the contents file into that folder and delete the old file.
From your .app example, I assume you are using MacOS. Therefore you will need to test this script yourself since I don't have MacOS, but I think it should be doing what you want. Execute it as bash script.sh and it will give you your desired directory test.app/contents in the current working directory.
#! /bin/bash
read -rp 'file: ' file
if [ -e "$file" ]; then
if [ -e "$file"/contents ]; then
base=$(basename "$file")
mkdir "$base"
cp -R "$file"/contents "$base"
rm -rf "$file"
else
echo "The specified file $file has no directory 'contents'."
fi
else
echo "The specified file $file does not exist."
fi

Linux shell script to copy and rename multiple files

I have this snippet:
#!/bin/bash
parent=/parent
newfolder=/newfolder
mkdir "$newfolder"
for folder in "$parent"/*; do
if [[ -d $folder ]]; then
foldername="${folder##*/}"
for file in "$parent"/"$foldername"/*; do
filename="${file##*/}"
newfilename="$foldername"_"$filename"
cp "$file" "$newfolder"/"$newfilename"
done
fi
done
I do need to turn it around in a way that the copied files would be named after the folder they are being moved to (e.g. moving to the /root/Case22 files would be renamed to case22_1.jpg, case22_2.docx, case22_3.JPG etc). The files would be copied from USB and both destination and source directries would be entered by the user. I have written everything else and it works apart from actual renaming and thought I could adapt this snippet.
thanks
p.s. the snippet is written by Jahid and found on stackoverflow
you can try something like this;
#!/bin/bash
parent=/root
a=1
for file in $parent/Case22*; do
filename="${file%.*}"
extension="${file##*.}"
newfilename=$(printf "$filename"_"$a"."$extension")
mv -- "$file" "$newfilename"
let a=a+1
done
Thanks for the help. I have found the solution and thought I might post it here in case someone else will be looking at this.
As the title suggests I needed a Linux shell script to copy and rename multiple files keeping original directory tree (the file source and archive locations would be specified by the user of the script). Here is the code that I came up with after few days research of different sources (it includes a trap so only one instance of script would be running at a time):
lockdir=/var/tmp/mylock #directory for lock file creation
pidfile=/var/tmp/mylock/pid #directory to get the process ID number
if ( mkdir ${lockdir} ) 2> /dev/null; then #main argument to create lock file
echo $$ > $pidfile #if successful script will proceed, otherwise it will skip to the else part of the statement at the end of the script
trap 'rm -rf "$lockdir"; exit $?' INT TERM EXIT #trap to capture reasons of script termination and removal of the lock file so it could be launched again
#start of the main script body, part of successful "if" statement
# read entry_for_testing_only #request for user entry to keep script running and try to run another script instance
findir="$2/$(basename "$1")" #variable that defines final directory to which files from USB will be copied
if [ ! -d "$1" ]; then #testing if first directory entry is a valid directory’’
echo "$1" "is not a directory"
echo ""
exit
else
if [ ! -d "$2" ]; then #testing if second entry is a valid directory
echo "archive directory non existant"
exit
else
if [ -d "$findir" ] && [ "$(ls -A "$findir")" ]; then #testing if second entry directory contains the same name folders and if the folders are empty - to avoid file overwriting
echo "such folder already there and it's not empty"
exit
else
if [ ! -d "$findir" ] ; then #last archive directory argument to create final archive directory
mkdir "$findir"
else true
fi
fi
fi
fi
rsync -a "$1"/ "$findir" #command to copy all files from the source to the archive retaining the directory tree
moved_files="$(find "$findir" -type f)" #variable that finds all files that have been copied to the archive directory
for file in $moved_files; do #start of the loop that renames copied files
counter="$((counter+1))" #incrementation variable
source_name="$(basename "$1")" #variable that captures the name of the source directory
new_name="$source_name"_"$counter" #variable that puts start of the file name and incrementation element together
if echo "$file" | grep "\." #argument that captures the extension of the file
then
extension="$(echo "$file" | cut -f2 -d. )"
else
extension=
fi
full_name="$new_name"."$extension" #variable that defines the final new name of the file
dir="$(dirname "${file}")" #variable that captures the directorry address of currently looped file
mv "$file" "$dir/$full_name" #move command to rename currently looped file with the final new name
done
#end of the main script body, unsuccessful "if" statement continues here
else
echo "Another instance of this script is already running. PID: $(cat $pidfile)"
fi

Issue in Bash script

I have a bash script which creates a directory if not already present and moves all the files to the newly created directory.
The bash script I have is returning is not working and the error is receive is
./move.sh: line 5: =/data/student/stud_done_11-11-2013: No such file or directory
already present
mv: missing destination file operand after `a.xml'
Try `mv --help' for more information.
The bash script is:
# Back up
if [ $# = 1 ]
then
$dir="/data/student/stud_done_$1"
echo $dir
if [ ! -d $dir ]; then
mkdir $dir
else
echo "already present"
fi
cd /data/student/stud_ready
mv * $dir
else
echo "No files to move"
fi
I invoke the script as follows:
./move.sh "11-11-2013"
What is the error in my script.
Here (on line 5)...
$dir="/data/student/stud_done_$1"
You meant...
dir="/data/student/stud_done_$1"

Bash: If statement nested in for loop

I am writing a simple script to check if an entered directory path exists. This is what I have
echo "Please specify complete directory path"
read file_path
for file in $file_path; do
if [[ -d "$file" ]]; then
echo "$file is a directory"
break
else
echo "$file is not a directory, please try again."
fi
done
What I need is if it is not a directory to go back and ask for the file path again.
Thanks.
How about this?
echo "Please specify complete directory path"
while read file; do
if [[ -d "$file" ]]; then
echo "$file is a directory"
break
fi
echo "$file is not a directory, please try again."
done
No need to split the path into its parts, testing the entire path with -d will tell you whether or not it is a directory. You need to put the entire test into a while loop until the user gets it right:
#/bin/sh
set -e
file_path=''
while [ ! -d "$file_path" ]
do
echo "Please specify complete directory path"
read file_path
if [ ! -d "$file_path" ]
then
echo "$file_path is not a directory, please try again."
fi
done
I can use it like this
$ sh /tmp/test.sh
Please specify complete directory path
foobar
foobar is not a directory, please try again.
Please specify complete directory path
/var/www

Resources