List all the files with prefixes from a for loop using Bash

南楼画角 提交于 2019-12-10 23:33:25

问题


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 tagged bash - unless you need POSIX compliance, use a bash shebang line to take advantage of all that bash 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!