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
cdin 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
$filesis an array with file names$fcontains the directory$dis the depth of search, default is 1 (only for specified folder)$filecontains the file name as$path_to_file/$filename
CodePudding user response:
What you see is the consequence of
/var/spool/bandit24being empty. In this case/var/spool/bandit24/*expands as itself. If you prefer that it expands as null you can enable thenullglobbash option before your for loop:shopt -s nullglob.As variable
mynameis assignedbandit24,cd /var/spool/$mynameis the same ascd /var/spool/bandit24. You should probably rewrite it ascd /var/spool/"$myname" || exit 1. Double quotes just in case themynamevalue contains spaces (it is not the case now but who knows what you will be doing next). And|| exit 1to abort your script if the directory does not exist and thecdcommand 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, variablefilewill take values like/var/spool/bandit24/foobar, not justfoobar. So you cannot use it with./$file. Solution: as youcdin the/var/spool/bandit24directory, 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
