问题
Here is a small[but complete] part of my bash script that finds and outputs all files in mydir if the have the prefix from a stored array. Strange thing I notice is that this script works perfectly if I take out the "-maxdepth 1 -name" from the script else it only gives me the files with the prefix of the first element in the array.
It would be of great help if someone explained this to me. Sorry in advance if there is some thing obviously silly that I'm doing. I'm relatively new to scripting.
#!/bin/sh
DIS_ARRAY=(A B C D)
echo "Array is : "
echo ${DIS_ARRAY[*]}
for dis in $DIS_ARRAY
do
IN_FILES=`find /mydir -maxdepth 1 -name "$dis*.xml"`
for file in $IN_FILES
do
echo $file
done
done
Output:
/mydir/Abc.xml
/mydir/Ab.xml
/mydir/Ac.xml
Expected Output:
/mydir/Abc.xml
/mydir/Ab.xml
/mydir/Ac.xml
/mydir/Bc.xml
/mydir/Cb.xml
/mydir/Dc.xml
回答1:
The loop is broken either way. The reason why
IN_FILES=`find mydir -maxdepth 1 -name "$dis*.xml"`
works, whereas
IN_FILES=`find mydir "$dis*.xml"`
doesn't is because in the first one, you have specified -name
. In the second one, find
is listing all the files in mydir
. If you change the second one to
IN_FILES=`find mydir -name "$dis*.xml"`
you will see that the loop isn't working.
As mentioned in the comments, the syntax that you are currently using $DIS_ARRAY
will only give you the first element of the array.
Try changing your loop to this:
for dis in "${DIS_ARRAY[@]}"
In this case, the surrounding double quotes are not necessary, so you could do:
for dis in ${DIS_ARRAY[@]}
The quotes are required if your array contained spaces, for example if you wanted to loop through the array arr=( "a a" "b b" )
.
Here's a test showing what's going on:
#!/bin/sh
arr=("a a" "b b")
echo using '$arr'
for i in $arr; do echo $i; done
echo using '${arr[@]}'
for i in ${arr[@]}; do echo $i; done
echo using '"${arr[@]}"'
for i in "${arr[@]}"; do echo $i; done
output:
using $arr
a
a
using ${arr[@]}
a
a
b
b
using "${arr[@]}"
a a
b b
See this related question for further details.
回答2:
@TomFenech's answer solves your problem, but let me suggest other improvements:
#!/usr/bin/env bash
DIS_ARRAY=(A B C D)
echo "Array is : "
echo ${DIS_ARRAY[*]}
for dis in "${DIS_ARRAY[@]}"
do
for file in "/mydir/$dis"*.xml
do
if [ -f "$file" ]; then
echo "$file"
fi
done
done
- Your shebang line references
sh
, but your question is taggedbash
- unless you need POSIX compliance, use abash
shebang line to take advantage of all thatbash
has to offer - To match files located directly in a given directory (i.e., if you don't need to traverse an entire subtree), use a glob (filename pattern) and rely on pathname expansion as in my code above - no need for
find
and command substitution. - Note that the wildcard char.
*
is UNquoted to ensure pathname expansion. - Caveat: if no matching files are found, the glob is left untouched (assuming the
nullglob
shell option is OFF, which it is by default), so the loop is entered once, with an invalid filename (the unexpanded glob) - hence the[ -f "$file" ]
conditional to ensure that an actual match was found (as an aside: using bashisms, you could use[[ -f $file ]]
instead).
来源:https://stackoverflow.com/questions/22365552/list-all-the-files-with-prefixes-from-a-for-loop-using-bash