searching for a file name in a directory and all its subdirectories not recognizing the file in the subdirectory - linux

#!/bin/bash
if(($#!=1))
then
echo "Please enter a file name: "
read f1
else
f1=$1
fi
while [ ! -f $f1 ]
do
echo "Please enter an existing file name: "
read f1
done
for file in *
do
if [ $file == $f1 ]
then
pwd
fi
echo "Check here 1"
done
for file in */*
do
if [ $file == $f1 ]
then
pwd
fi
echo "Check here 2"
done
This is my script, and I have the file f3.txt in the directory having this script and a subdirectory in it.
And I want to check where this file is located. when entering the main directory, it does enter the if successfully when they find the file, but when entering the subdirectory, it won't enter the if even though f3.txt is in the subdirectory.
To clarify, the first for loop works perfectly fine, when entering the second for loop, it does echo check here 2 perfectly according to how many files there is in the subdirectory, but doesn't enter the if despite having a file f3.txt in this subdirectory

The immediate problem is that the wildcard expands to the directory name and the file name, and so of course it will not be equal to just the input file name.
if [ "$(basename "$file")" = "$f1" ]
strips the directory name before comparing (and also fixes quoting and syntax; the string equality comparison operator in sh is = and although Bash also allows == as a synonym, I can see no reason to prefer that)
... though properly speaking, you probably want
find . -name "$f1" -maxdepth 2 -ls
or maybe take out -maxdepth 2 if you want to traverse subdirectories of subdirectories etc.

Related

How can I remove the extension of specific files in a directory?

I want to remove the extension of specific files with a given extension.
So for instance, in a directory foobar, we have foo.txt, bar.txt foobar.jpg.
Additionally, the extension that I've put in to be removed is txt
After calling the program, my output should be foo bar foobar.jpg
Here is my code so far:
#!/bin/bash
echo "Enter an extension"
read extension
echo "Enter a directory"
read directory
for file in "$directory"/*; do //
if [[ $file == *.txt ]]
then
echo "${file%.*}"
else
echo "$file"
fi
done
However when I run this on a given directory, nothing shows up.
I'm assuming that there is a problem with how I referred to the directory ( in the line where I placed a //) and I've tried to research on how to solve it but to no avail.
What am I doing wrong?
If files do exist in a valid directory you've entered then they should show up — with one exception. If you are using ~/ (shorthand home directory) then it will be treated as plain text in your for loop. The read variable should be substituted into another variable so the for loop can treat it as a directory (absolute paths should work normally as well).
#!/bin/bash
echo "Enter an extension"
read -r extension
echo "Enter a directory"
read -r directory
dir="${directory/#\~/$HOME}"
for file in "$dir"/*; do
if [[ $file == *."$extension" ]]
then
echo "${file%.*}"
else
echo "$file"
fi
done
You can simplify your for-loop:
for file in "$directory"/*; do
echo "${f%.$extension}";
done
The % instructions removes only matching characters. If nothing matches, the original string (here f) is returned.
When you write bash scripts it's more common to pass arguments to your script via command line arguments rather than by reading it from standard input via read program.
Passing arguments via command line:
#!/bin/bash
# $# - a bash variable which holds a number of arguments passed
# to script via command line arguments
# $0 holds the name of the script
if [[ $# -ne 2 ]]; then # checks if exactly 2 arguments were passed to script
echo "Usage: $0 EXTENSION DIRECTORY"
exit -1;
fi
echo $1; # first argument passed to script
echo $2; # second arugment passed to script
This approach is more efficient because a subprocess is spawn for read command to run and there is no subprocess spawn for reading command line arguments.
There is no need to manually loop through directory, you can use find command to find all files with given extension within given directory.
find /path/to/my/dir -name '*.txt'
find $DIRECTORY -name "*.$EXTENSION"
# note that single quotes in this context would prevent $EXTENSION
# variable to be resolved, so double quotes are used " "
# find searches for files inside $DIRECTORY and searches for files
# matching pattern '*.$EXTENSION'
Note that to avoid bash filename expansion sometimes it is required to wrap actual pattern in single quotes ' ' or double quotes " ". See Bash Filename Expansion
So now your script can look like this:
#!/bin/bash
if [[ $# -ne 2 ]]; then
echo "Usage: $0 EXTENSION DIRECTORY"
exit -1;
fi
$EXTENSION = $1 # for better readability
$DIRECTORY = $2
for file in `find $DIRECTORY -name "*.$EXTENSION"`; do
mv $file ${file%.$EXTENSION}
done
Construct ${file%.$EXTENSION} is called Shell Parameter Expansion it searches for occurrence of .$EXTENSION inside file variable and deletes it.
Notice that in the script it is easy to pass extension as directory and vice versa.
We can check if second argument is in fact directory, we can use following construction:
if ! [[ -d $DIRECTORY ]]; then
echo $DIRECTORY is not a dir
exit -1
fi
This way we can exit from the script earlier with more readable error.
To sum up entire script could look like this:
#!/bin/bash
if [[ $# -ne 2 ]]; then
echo "Usage: $0 EXTENSION DIRECTORY"
exit -1;
fi
EXTENSION=$1 # for better readability
DIRECTORY=$2
if ! [[ -d $DIRECTORY ]]; then
echo $DIRECTORY is not a directory.
exit -1
fi
for file in `find $DIRECTORY -name "*.$EXTENSION"`; do
mv $file ${file%.$EXTENSION}
done
Example usage:
$ ./my-script.sh txt /path/to/directory/with/files

Moving files in different folder changing the names

I am trying to write a script to move some file in a common folder.
Basically I have n folders and in each of them there is a file called xmu.dat; I want to copy these files in a different folder changing its names.
This is the code I came up with (I have never written a script before...), but I get some errors:
echo "Folders found:"
for folder in */
do
echo "$folder"
name = ${folder//[\/]/}
cp ./"$folder"/xmu.dat ./OutputFiles/name
done
As fedorqui said, the issue with your code is the presence of whitespaces around the '='.
If you want to check if a file exists, you can use the '-f' option, as:
if [ -f "$file" ]
then
echo "$file found."
else
echo "$file not found."
fi

Bash scripting and comparing 2 directories - Beginner

My problem is that i have to check what files are included in the $directory, then i have to make a new file with name specified by me and compare if the name doesn't already exist in this directory (compare 2 directories).
Below is my code:
directory=$(pwd -L "/$nameProject")
read -p "Enter repo name: " nameRepo
# Check if repo name exists in $directory
if [$(find "$directory/$nameProject" -path "$directory/$nameProject/*")==$("$directory/$nameProject/$nameRepo")]; then
instruction..
fi
Thank you for any help!
Did you try
if [[ ! -d "$directory/$nameProject/$nameRepo" && ! -f "$directory/$nameProject/$nameRepo"]] ; then
mkdir "$directory/$nameProject/$nameRepo"
fi
You can split the above if loop into two and print appropriate error by removing !
Spaces are important to the shell. So is quoting. You need spaces around [ and == and ] (though ]; is ok). (Also technically the comparison operator is = and not ==.).
Also find can return more than one result which will cause problems for your test.
If you want to test whether a directory (or file) with a given name exists then you don't need (or want) to use find. You can just use the -d and -f (and -e) tests of the [ test binary/built-in directly(spec, bashref).
if [ -d path/to/directory ]; then
echo "Was a directory"
else
echo "Was not a directory"
fi

Bash script - how to keep looping 'find' command until file/s are found?

I am very new to linux scripting & am trying to set up a simple loop which will:
Ask user for file name
Search a specific directory for the file
If no files are found, ask the user to reinput a file name
If files are found, move on to the next step of the script
This is what I have so far, but it is not looping at all(i.e when no files are found, it is not asking the user to re-enter a file name. )
#!/bin/bash
read -p "Enter file name: " file
find /directory/ -name "$file" -print
while [ "$?" -ne 0 ]; do
read -p "File not found. Please re-enter file name: " file
find /directory/ -name "$file" -print
done
echo "rest of script etc"
Any help is appreciated! :)
The easiest way to do this is probably using globstar (available with bash 4)
#!/bin/bash
shopt -s globstar
while true; do
read -p "Enter file name: " file
for f in /directory/**/"$file"; do
echo "$f"
break 2 # escape both loops
done
echo "'$file' not found, please try again."
done
echo "rest of script etc"
It's also possible to do with find, but slightly annoying, given that you can't use standard UNIX exit statuses:
#!/bin/bash
read -p "Enter file name: " file
found=$(find /directory/ -name "$file" -print -quit)
while [[ -z $found ]]; do
read -p "File not found. Please re-enter file name: " file
found=$(find /directory/ -name "$file" -print -quit)
done
echo "$found"
echo "rest of script etc"
Normally I wouldn't recommend parsing the output of find, but in this case we're only concerned as to whether or not there is any output.
The easiest and most portable way might be this:
# Loop until user inputted a valid file name
while true ; do
# Read input (the POSIX compatible way)
echo -n "Enter file name: "
read file
# Use find to check if the file exists
[ $(find /etc -type f -name "$file" 2>/dev/null | wc -l ) != "0" ] && break
# go to next loop if the file does not exist
done
echo "Ok, go on here"

Check if argument is a file or directory

I am trying to check if an argument is a directory or a file. I want to put a / after each directory name and a * after every executable file. I know ls uses -F to get this information but I can't figure this out in my script.
Here is my code:
echo -n "Please enter Directory name you wish to search: "
read dir
for filename in "/home/me/Desktop/$dir"/*
do
if (-F $filename)
then
echo $filename
fi
done
[ -f "$filename" ] is true for files, [ -d "$dirname" ] is true for directories.

Resources