Remove File on One Level of Directories only in KSH - bash

I have a rm command which clears all the files in a particular directory.
#!/usr/bin/ksh
cd /asd/ded/ses/ddd/rty/leg/
rm *.sas7bdat
rm p_bt*
Unfortunately it clears all the files under this directory, but now I just want it to clear in "parent directory" i.e. "/asd/ded/ses/ddd/rty/leg/" and not in "/asd/ded/ses/ddd/rty/leg/21_11" which is the child directory inside it.
I know level rm is possible in bash. Does it change for KSH and if yes then how.

LonelySoul,
Chepner is correct. The default for 'rm' in ksh is to only remove the files in the current directory. You can remove files from the lower directories (recursively) by adding the '-r' option.
If you are observing different behavior, you may have an alias setup somewhere in your profile. Try entering 'whence rm' to see if there is an alias that is causing you unexpected behavior.
Examples.
>pwd
/tmp
>touch abc.txt
>mkdir ced
>touch ced/abc.txt
>rm abc.txt (will remove abc.txt in /tmp, but leave the file in directory ced.
>whence rm
rm -f

Related

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.

BASH: Copy all files and directories into another directory in the same parent directory

I'm trying to make a simple script that copies all of my $HOME into another folder in $HOME called Backup/. This includes all hidden files and folders, and excludes Backup/ itself. What I have right now for the copying part is the following:
shopt -s dotglob
for file in $HOME/*
do
cp -r $file $HOME/Backup/
done
Bash tells me that it cannot copy Backup/ into itself. However, when I check the contents of $HOME/Backup/ I see that $HOME/Backup/Backup/ exists.
The copy of Backup/ in itself is useless. How can I get bash to copy over all the folders except Backup/. I tried using extglob and using cp -r $HOME/!(Backup)/ but it didn't copy over the hidden files that I need.
try rsync. you can exclude file/directories .
this is a good reference
http://www.maclife.com/article/columns/terminal_101_using_rsync_locally
Hugo,
A script like this is good, but you could try this:
cp -r * Backup/;
cp -r .* Backup/;
Another tool used with backups is tar. This compresses your backup to save disk space.
Also note, the * does not cover . hidden files.
I agree that using rsync would be a better solution, but there is an easy way to skip a directory in bash:
for file in "$HOME/"*
do
[[ $file = $HOME/Backup ]] && continue
cp -r "$file" "$HOME/Backup/"
done
This doesn't answer your question directly (the other answers already did that), but try cp -ua when you want to use cp to make a backup. This recurses directories, copies rather than follows links, preserves permissions and only copies a file if it is newer than the copy at the destination.

cp: silence "omitting directory" warning

I'm using the command cp ./* "backup_$timestamp" in a bash script to backup all files in directory into a backup folder in a subdirectory. This works fine, but the script keeps outputting warning messages:
cp: omitting directory `./backup_1364935268'
How do I tell cp to shut up without silencing any other warnings that I might want to know about?
The solution that works for me is the following:
find -maxdepth 1 -type f -exec cp {} backup_1364935268/ \;
It copies all (including these starting with a dot) files from the current directory, does not touch directories and does not complain about it.
Probably you want to use cp -r in that script. That would copy the source recursively including directories. Directories will get copied and the messages will disappear.
If you don't want to copy directories you can do the following:
redirect stderr to stdout using 2>&1
pipe the output to grep -v
script 2>&1 | grep -v 'omitting directory'
quote from grep man page:
-v, --invert-match
Invert the sense of matching, to select non-matching lines.
When copying a directory, make sure you use -R
cp -R source source_duplicate_copy_name
-R, -r, --recursive copy directories recursively
--reflink[=WHEN] control clone/CoW copies. See below
--remove-destination remove each existing destination file before
attempting to open it (contrast with --force)
--sparse=WHEN control creation of sparse files. See below
--strip-trailing-slashes remove any trailing slashes from each SOURCE

Copy files from one directory into an existing directory

In bash I need to do this:
take all files in a directory
copy them into an existing directory
How do I do this? I tried cp -r t1 t2 (both t1 and t2 are existing directories, t1 has files in it) but it created a directory called t1 inside t2, I don't want that, I need the files in t1 to go directly inside t2. How do I do this?
What you want is:
cp -R t1/. t2/
The dot at the end tells it to copy the contents of the current directory, not the directory itself. This method also includes hidden files and folders.
cp dir1/* dir2
Or if you have directories inside dir1 that you'd want to copy as well
cp -r dir1/* dir2
If you want to copy something from one directory into the current directory, do this:
cp dir1/* .
This assumes you're not trying to copy hidden files.
Assuming t1 is the folder with files in it, and t2 is the empty directory. What you want is something like this:
sudo cp -R t1/* t2/
Bear in mind, for the first example, t1 and t2 have to be the full paths, or relative paths (based on where you are). If you want, you can navigate to the empty folder (t2) and do this:
sudo cp -R t1/* ./
Or you can navigate to the folder with files (t1) and do this:
sudo cp -R ./* t2/
Note: The * sign (or wildcard) stands for all files and folders. The -R flag means recursively (everything inside everything).
cp -R t1/ t2
The trailing slash on the source directory changes the semantics slightly, so it copies the contents but not the directory itself. It also avoids the problems with globbing and invisible files that Bertrand's answer has (copying t1/* misses invisible files, copying `t1/* t1/.*' copies t1/. and t1/.., which you don't want).
For inside some directory, this will be use full as it copy all contents from "folder1" to new directory "folder2" inside some directory.
$(pwd) will get path for current directory.
Notice the dot (.) after folder1 to get all contents inside folder1
cp -r $(pwd)/folder1/. $(pwd)/folder2
Nov, 2021 Update:
This code with Flag "-R" copies perfectly all the contents of "folder1" to existing "folder2":
cp -R folder1/. folder2
Flag "-R" copies symbolic links as well but Flag "-r" skips symbolic links so Flag "-R" is better than Flag "-r".
The latest GNU Grep 3.7:
-R, --dereference-recursive
For each directory operand, read and process all files in that directory,
recursively, following all symbolic links.
-r, --recursive
For each directory operand, read and process all files in that directory,
recursively. Follow symbolic links on the command line, but skip symlinks
that are encountered recursively. Note that if no file operand is given,
grep searches the working directory. This is the same as the
‘--directories=recurse’ option.
Depending on some details you might need to do something like this:
r=$(pwd)
case "$TARG" in
/*) p=$r;;
*) p="";;
esac
cd "$SRC" && cp -r . "$p/$TARG"
cd "$r"
... this basically changes to the SRC directory and copies it to the target, then returns back to whence ever you started.
The extra fussing is to handle relative or absolute targets.
(This doesn't rely on subtle semantics of the cp command itself ... about how it handles source specifications with or without a trailing / ... since I'm not sure those are stable, portable, and reliable beyond just GNU cp and I don't know if they'll continue to be so in the future).
the correct option should be -T. used with -r to copy recursively.
$ cp -r -T t1 t2

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