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

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

Related

Can not locate a file in a bash script?

I am running a shell script which expects a file in a directory but I can not seem to locate it.
This is my shell script
#!/usr/bin/env bash
# expects a file to be present in current directory called INPUT_FILE
# this is the value set in the jenkins config
if [ ! -f INPUT_FILE ] ;then
echo "file ${INPUT_FILE} does not exist"
exit 1
fi
And in windows I am running a shell script from a directory like this
D:\scripts> ./all/script.sh
I tried to put INPUT_FILE.csv in scripts folder and also in all folder but it does not seem to work. Where should this file be present?
Make sure you have the correct filename.
Windows hides the extension of a file, when you look for INPUT_FILE.csv use
if [ ! -f INPUT_FILE.csv ] ;then
echo "file INPUT_FILE.csv does not exist"
exit 1
fi
You tried to use the variable INPUT_FILE. When you want this, try
input_file="INPUT_FILE.csv"
if [ ! -f "${input_file}" ]; then
echo "file ${input_file} does not exist"
exit 1
fi
Also note that bash is case sensitive, so INPUT_FILE.csv is different from input_file.csv.
It's better to list files first to verify the extension and all file names in the directory then check for the existence of the files.
#!/usr/bin/env bash
ALL_FILES=$(ls -I "*.sh") # This will list all file except .sh
echo "Files in current Directory $ALL_FILES"
INPUT_FILE="INPUT_FILE" # or INPUT_FILE="INPUT_FILE.csv"
if [ ! -f $INPUT_FILE ] ;then
echo "file ${INPUT_FILE} does not exist"
exit 1
else
echo "file exist ${INPUT_FILE}"
exit 0
fi
The first advantage, It will list all the file and the second one, If exist you will get the output.

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

Bash does not detect that file exists

I have made a bash alias to execute scripts before and after the cd command. The only issue is it does not execute the files.
Here is my code
cd(){
if [ -d "./.dinit" ]
then
echo "dinit file exists"
source ./.dinit
fi
builtin cd $#
if [ -d "./.init" ]
then
echo "init file exists"
source ./.init
fi
}
In the .init file I have the command echo hello and in the .dinit I have echo goodbye
When I get this working I am going to put PATH= statements in the files along with alias.
Does anyone know how I can get the commands to execute?
Your checks right now look for directories, which you then try to source. That doesn't really make any sense, so I'm assuming that those are really the files you want to source. In which case, you should use -f to check for a regular file instead:
cd(){
if [ -f "./.dinit" ]
then
echo "dinit file exists"
source ./.dinit
fi
builtin cd "$#"
if [ -f "./.init" ]
then
echo "init file exists"
source ./.init
fi
}

Bash script - Nested If Statement for If File Doesn't Exist

I'm trying to compile a script that will read user input, and check if the file after the y/n statement. Then it will make files executable. I think the problem with my script is conditional ordering but check it out yourself:
target=/home/user/bin/
cd $target
read -p "This will make the command executable. Are you sure? (y/n)" CONT
if [ "$CONT" == "y" ];
then
chmod +x $1
echo "File $1 is now executable."
else
if [ "$(ls -A /home/user/bin/)" ];
then
echo "File not found."
else
echo "Terminating..."
fi
fi
As I said, I need the script to scan for the file after the y/n statement is printed. The script works fine how it is but still gives the "file is now executable" even if the argument file doesn't exist (but just gives the standard system "cannot find file" message after the echo'd text).
Your script is mostly correct, you just need to check if the file exists first. Also, it's not the best practice to use cd in shell scripts and not needed here.
So re-writing it
#!/bin/bash
target="/home/user/bin/$1"
if [[ ! -f $target ]]; then
echo "File not found."
else
read -p "This will make the command executable. Are you sure? (y/n) " CONT
if [[ $CONT == "y" ]]; then
chmod +x "$target"
echo "File $1 is now executable."
else
echo "Terminating..."
fi
fi
To get an understanding:
Your script will take one argument (a name of a file).
You ask if you want to make that file executable.
If the answer is 'yes', you make the file executable.
Otherwise, you don't.
You want to verify that the file exists too?
I'm trying to understand your logic. What does this:
if [ "$(ls -A /home/user/bin/)" ];
suppose to do. The [ ... ] syntax is a test. And, it has to be one of the valid tests you see here. For example, There's a test:
-e file: True if file exists.
That mean, I can see if your file is under /home/user/bin:
target="/home/user/bin"
if [ -e "$target/$file" ] # The "-e" test for existence
then
echo "Hey! $file exists in the $target directory. I can make it executable."
else
echo "Sorry, $file is not in the $target directory. Can't touch it."
fi
Your $(ls -A /home/user/bin/) will produce a file listing. It's not a valid test like -e unless it just so happens that the first file in your listing is something like -e or -d.
Try to clarify what you want to do. I think this is something more along the lines you want:
#! /bin/bash
target="/home/user/bin"
if [ -z "$1" ] # Did the user give you a parameter
then
echo "No file name given"
exit 2
fi
# File given, see if it exists in $target directory
if [ ! -e "$target/$1" ]
then
echo "File '$target/$1' does not exist."
exit 2
fi
# File was given and exists in the $target directory
read -p"Do you want $target/$1 to be executable? (y/n)" continue
if [ "y" = "$continue" ]
then
chmod +x "$target/$1"
fi
Note how I'm using the testing, and if the testing fails, I simply exit the program. This way, I don't have to keep embedding if/then statements in if/then statements.

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