How to refer to the files in subdirectory in shell program? - shell

I have a script called idk.sh at the root of a folder called autograder.
I also have a subdirectory in autograder called hw1 which contains some .sh files. I tried to print out the file name and contents but I failed. actually I tried /hw1, /hw1/, /hw1/* and failed. I dont really understand why I failed to fetch files and hope someone could answer me as I looked up the web and found that the approach should be /hw1/*. Thank you.
#!/bin/sh
for file in /hw1/*
do
echo $file
if [ -f $file ]
then
cat $file
echo $file
fi
done
~
~

I would simply do a find to achieve this
find /hw/ -type f -print -exec cat {} \;

A directory path starting with / means an absolute path, that is, a path from the root of the filesystem. Relative paths start with any character other than / (and \0, but that's a technicality). You'll also want to use a reference to the directory of the script, to be able to run the script from other directories.
See also:
How do I determine the location of my script?
Bash Pitfalls
Linux Filesystem Tree Overview

Related

How to make script independent from where it is executed

I am running into the problem of commands failing because I expect them to be executed at some directory and that is not the case.
For example I want to do:
pdfcrop --margins '0 0 -390 0' $pag "$pag"_1stCol.pdf
to create a new pdf document, and then
mv `\ls /home/dir | grep '_1stCol'` /home/gmanglano/dir/columns
The problem is that the mv command is failing because it finds the document, it is trying to move that file found FROM the directory where I executed the script, not from where it was found.
This is happening to me somewhat often and I feel there is a concept I am missing or I am thinking this the wrong way arround.
The error I get is:
mv: cannot stat '1stCol.pdf': No such file or directory
When there is, in fact, said fail, it just is not in the directory I launched the script.
Instead of monkeying with ls and backticks and all that, just use the find command. It's built for to find files and then execute a command based on the results of that find:
find /home/dir -name "*_1stCol.pdf" -exec mv {} /home/gmanglano/dir/columns \;
This is finding files in /home/dir that match the name *_1stCol.pdf and then moves them. The {} is the token for the found file.
Don't parse the output of ls: if you simplify the mv command to
mv /home/dir/*_1stCol.pdf /home/gmanglano/dir/columns
then you won't have an issue with being in the wrong directory.

How can I compare filename without getting permission denied message in bash?

I want to look through all files in my directory and subdirectory
then delete files with special name
Here is my code
for filename in $1*;do
if("$filename" == "hello.txt");then
echo "WOW!"
fi
done
My test directory is TEST/ and there are two files. one name "hello.txt" and "world.txt";However, when I run the code I receive
noStrange.sh: line 2: TEST/hello.txt: Permission denied
noStrange.sh: line 2: TEST/world.txt: Permission denied
I tried the command chmod u+x scriptname, it doesn't work
This is what I input
sh scriptname TEST/
Can anyone tell me what is wrong with the script?
Use basename command to get the basename of a file from file path variable.
for filename in $1*;do if [[ $(basename "$filename") == "hello.txt" ]] ; then echo "wow";fi; done
Or
Use find command. This would search through all the files exists in the current folder as well it's sub folders.
find . -name 'hello.txt'
The immediate answer is that your syntax for tests is wrong; you should have
if ["$filename" == "hello.txt"]; then
etc. However, there are a few issues with your code. Since $filename will match TEST/hello.txt instead of hello.txt, you probably won't get the behavior you want. Also, if you're looking to just delete files with certain names, you probably want a normal UNIX command like
rm TEST/hello.txt
If there are patterns you want do delete, you can use glob/wildcards, or a combination of find, xargs and rm. E.g.
find TEST -name 'hello*.txt' | xargs rm

File ownership not changing in bash script

Im trying to run this script which basically copies an uploaded file to another directory - when I run it, the file gets copied ok but the ownership of the file does not get changed to sales1upload.dba as I expected while it produces the following error on output:
chown: cannot access `test1.txt': No such file or directory
#!/bin/bash
BASE_DIR="/home/sales1upload/upload"
NEW_BASE_DIR="/bbc/prod/today"
current_time=$(date "+%Y.%m.%d-%H.%M.%S")
for file in $(ls ${BASE_DIR});
do
filename=${file}
new_filename=$filename.$current_time
#set user permissions as desired
chown sales1upload.dba "$filename"
cp -prf ${BASE_DIR}/${filename} ${NEW_BASE_DIR}/"moved_files"/$new_filename
cp -prf ${BASE_DIR}/${filename} ${NEW_BASE_DIR}
rm ${BASE_DIR}/${filename}
done
Where am I going wrong with the file ownership in the script?
My quick guess: You're not running this in your Base directory, thus you cannot reference the file without specifying the base in the chmod argument. Change to:
chown sales1upload.dba "${BASE_DIR}/${filename}"
I'd like to add that though mine is the straightforward solution to your issue, getting rid of that ls as the other answers suggest is the way to go here.
You are asking ls to return a list of files in a directory, but they exist relative to that directory, not relative to the current directory.
As pointed out in comments, you should not be using ls for this at all. Fixing the ls to a simple wildcard will also incidentally solve your problem, but now you need to refactor the body of the loop to cope with a full path instead of just a plain file name. (You were already doing the opposite in a couple of places, so this should have been a simple bug to troubleshoot yourself.)
for file in "$BASE_DIR"/*; do
filename=$(basename "$file")
new_filename=$filename.$current_time
chown sales1upload.dba "$file"
cp -prf "$file" "$NEW_BASE_DIR/moved_files/$new_filename"
cp -prf "$file" "$NEW_BASE_DIR"
rm "$file"
done
Find files with find and not with ls. If you use find, you have the correct path. In your example you iterate over the relative path and not the absolute path.

Shell Script to update the contents of a folder - 2

I wrote this piece of code this morning.
The idea is, a text file (new.txt) has the details about the directory structure and the files in the directory.
Read new.txt, create the same directory structure at a destination directory (here it is /tmp), copy the source files to the corresponding destination directory.
Script
clear
DEST_DIR=/tmp
for file in 'cat new.txt'
do
mkdir -p $file
touch $file
echo 'ls -ltr $file'
cp -rf $file $DEST_DIR
find . -name $file -type f
cp $file $DEST_DIR
done
Contents of new.txt
Test/test1/test1.txt
Test/test2/test2.txt
Test/test3/test3.txt
Test/test4/test4.txt
The issue is, it executes the code, creates the directory structure, but instead of creating it at the end, it creates directories named test1.txt, test2.txt, etc. I have no idea why this is happening.
Another question: For Turbo C, C++, there is an option to check the execution flow? Is there something available in Unix, Perl and shell scripting to check the execution flow?
The script creates these directories because you tell it to on the line mkdir -p $file. You have to extract the directory path from you filename. The standard command for this is dirname:
dir=`dirname "$file"`
mkdir -p -- "$dir"
To check the execution flow is to add set -x at the top of your script. This will cause all lines that are executed to be printed to stderr with "+ " in front of it.
you might want to try something like rsync

bash script for copying files between directories

I am writing the following script to copy *.nzb files to a folder to queue them for Download.
I wrote the following script
#!/bin/bash
#This script copies NZB files from Downloads folder to HellaNZB queue folder.
${DOWN}="/home/user/Downloads/"
${QUEUE}="/home/user/.hellanzb/nzb/daemon.queue/"
for a in $(find ${DOWN} -name *.nzb)
do
cp ${a} ${QUEUE}
rm *.nzb
done
it gives me the following error saying:
HellaNZB.sh: line 5: =/home/user/Downloads/: No such file or directory
HellaNZB.sh: line 6: =/home/user/.hellanzb/nzb/daemon.queue/: No such file or directory
Thing is that those directories exsist, I do have right to access them.
Any help would be nice.
Please and thank you.
Variable names on the left side of an assignment should be bare.
foo="something"
echo "$foo"
Here are some more improvements to your script:
#!/bin/bash
#This script copies NZB files from Downloads folder to HellaNZB queue folder.
down="/home/myusuf3/Downloads/"
queue="/home/myusuf3/.hellanzb/nzb/daemon.queue/"
find "${down}" -name "*.nzb" | while read -r file
do
mv "${file}" "${queue}"
done
Using while instead of for and quoting variables that contain filenames protects against filenames that contain spaces from being interpreted as more than one filename. Removing the rm keeps it from repeatedly producing errors and failing to copy any but the first file. The file glob for -name needs to be quoted. Habitually using lowercase variable names reduces the chances of name collisions with shell variables.
If all your files are in one directory (and not in multiple subdirectories) your whole script could be reduced to the following, by the way:
mv /home/myusuf3/Downloads/*.nzb /home/myusuf3/.hellanzb/nzb/daemon.queue/
If you do have files in multiple subdirectories:
find /home/myusuf3/Downloads/ -name "*.nzb" -exec mv {} /home/myusuf3/.hellanzb/nzb/daemon.queue/ +
As you can see, there's no need for a loop.
The correct syntax is:
DOWN="/home/myusuf3/Downloads/"
QUEUE="/home/myusuf3/.hellanzb/nzb/daemon.queue/"
for a in $(find ${DOWN} -name *.nzb)
# escape the * or it will be expanded in the current directory
# let's just hope no file has blanks in its name
do
cp ${a} ${QUEUE} # ok, although I'd normally add a -p
rm *.nzb # again, this is expanded in the current directory
# when you fix that, it will remove ${a}s before they are copied
done
Why don't you just use rm $(a}?
Why use a combination of cp and rm anyway, instead of mv?
Do you realize all files will end up in the same directory, and files with the same name from different directories will overwrite each other?
What if the cp fails? You'll lose your file.

Resources