I am trying to iterate all files in a directory with for loop:
#!/bin/bash
myname="bandit24"
cd /var/spool/$myname
echo "Executing and deleting all scripts in /var/spool/$myname:"
for file in /var/spool/bandit24/*; # <----- here
do
if [ "$file" != "." -a "$file" != ".." ];
then
echo "Handling $file"
owner="$(stat --format "%U" ./$file)"
if [ "${owner}" = "bandit24" ]; then
timeout -s 9 60 ./$file
fi
rm -f ./$file
fi
done
But as a result I get the following:
Executing and deleting all scripts in /var/spool/bandit24:
Handling /var/spool/bandit24/*
stat: cannot stat './/var/spool/bandit24/*': No such file or directory
The program is not trying to iterate files in /var/spool/bandit24/
directory, but it tries to iterate /var/spool/bandit24/*
file itself. But I want to iterate files in /var/spool/bandit24/
directory. How to do it?
Additional question
What does cd /var/spool/$myname
mean (5 line)? As I understand, it is used for specifying the directory we are going to work in, am I right?
CodePudding user response:
The for-loop is basically sound. However, if the directory is empty, the loop will be executed once, with the variable file
containing the literal text /var/spool/bandit24/*
.
The stat
message is not from the for
-loop, but from one of the commands in the loop.
The correct way would be to test if the directory is empty before you continue. You could put something like
if [ $(find . -type f | wc -l) -eq 0 ] ; then
echo "Nothing to do"
exit 0
fi
right after the cd
.
Some other comments on your script.
- If you do a
cd
in the script, you don't need to specify the full path anymore. - Your quoting is not really consistent. That may not be a problem if your file names never contain spaces or strange characters, but I would, for example
timeout -s 9 60 "./$file"
andrm -f "./file"
/var/spool/bandit/*
will never contain.
or..
, so that test is useless.- You could also replace the test with
if [ -f "$file" ] ; then
CodePudding user response:
i've a bash script in my Github repo who iterates over all files in specified directory. You can specify the deepth of search, it's something like this.
mapfile files <<< "$(find "$f" -maxdepth "$d" ! -type d)"
for file in "${files[@]}"; do
file="$(tr -d '\n' <<< "$file")"
# implement your logic here
done
$files
is an array with file names$f
contains the directory$d
is the depth of search, default is 1 (only for specified folder)$file
contains the file name as$path_to_file/$filename
CodePudding user response:
What you see is the consequence of
/var/spool/bandit24
being empty. In this case/var/spool/bandit24/*
expands as itself. If you prefer that it expands as null you can enable thenullglob
bash option before your for loop:shopt -s nullglob
.As variable
myname
is assignedbandit24
,cd /var/spool/$myname
is the same ascd /var/spool/bandit24
. You should probably rewrite it ascd /var/spool/"$myname" || exit 1
. Double quotes just in case themyname
value contains spaces (it is not the case now but who knows what you will be doing next). And|| exit 1
to abort your script if the directory does not exist and thecd
command fails. This should avoid unwanted behaviors like executing and deleting all scripts in the current directory instead of the non-existing one...with
for file in /var/spool/bandit24/*
, if the directory is not empty, variablefile
will take values like/var/spool/bandit24/foobar
, not justfoobar
. So you cannot use it with./$file
. Solution: as youcd
in the/var/spool/bandit24
directory, simply writefor file in *
.You should really double quote all references to
$file
(stat --format "%U" "$file"
,timeout -s 9 60 ./"$file"
,rm -f "$file"
). If you don't you take real risks.
Try the following:
#!/bin/bash
myname="bandit24"
cd /var/spool/"$myname" || exit 1
echo "Executing and deleting all scripts in /var/spool/$myname:"
shopt -s nullglob
for file in *; do
echo "Handling $file"
owner=$(stat --format "%U" "$file")
if [ "$owner" = "$myname" ]; then
timeout -s 9 60 ./"$file"
fi
rm -f "$file"
done
CodePudding user response:
for f in $(find . -maxdepth 1 -type f); do
echo "current file is $f"
done