Bash glob parameter only shows first file instead of all files

后端 未结 4 774
遇见更好的自我
遇见更好的自我 2020-12-12 08:36

I want to run this cmd line script

$ script.sh   lib/* ../test_git_thing

I want it to process all the files in the /lib folder.

<         


        
相关标签:
4条回答
  • 2020-12-12 08:46

    In bash and ksh you can iterate through all arguments except the last like this:

    for f in "${@:1:$#-1}"; do
      echo "$f"
    done
    

    In zsh, you can do something similar:

    for f in $@[1,${#}-1]; do
      echo "$f"
    done
    

    $# is the number of arguments and ${@:start:length} is substring/subsequence notation in bash and ksh, while $@[start,end] is subsequence in zsh. In all cases, the subscript expressions are evaluated as arithmetic expressions, which is why $#-1 works. (In zsh, you need ${#}-1 because $#- is interpreted as "the length of $-".)

    In all three shells, you can use the ${x:start:length} syntax with a scalar variable, to extract a substring; in bash and ksh, you can use ${a[@]:start:length} with an array to extract a subsequence of values.

    0 讨论(0)
  • 2020-12-12 09:02

    This answers the question as given, without using non-POSIX features, and without workarounds such as disabling globbing.

    You can find the last argument using a loop, and then exclude that when processing the list of files. In this example, $d is the directory name, while $f has the same meaning as in the original answer:

    #!/bin/sh
    if [ $# != 0 ]
    then
            for d in "$@"; do :; done
            if [ -d "$d" ]
            then
                    for f in "$@"
                    do
                            if [ "x$f" != "x$d" ]
                            then
                                    echo "Processing $f file..."
                            fi
                    done
            fi
    fi
    

    Additionally, it would be a good idea to also test if "$f" is a file, since it is common for shells to pass the wildcard character through the argument list if no match is found.

    0 讨论(0)
  • 2020-12-12 09:04

    As correctly noted, lib/* on the command line is being expanded into all files in lib. To prevent expansion, you have 2 options. (1) quote your input:

    $ script.sh 'lib/*' ../test_git_thing
    

    Or (2), turn file globbing off. However, the option set -f will disable pathname expansion within the shell, but it will disable all pathname expansion (setting it within the script doesn't help as expansion is done by the shell before passing arguments to your script). In your case, it is probably better to quote the input or pass the first arguments as a directory name, and add the expansion in the script:

    DIR=$1
    for f in "$DIR"/*
    
    0 讨论(0)
  • 2020-12-12 09:04

    The argument list is being expanded at the command line when you invoke "script.sh lib/*" your script is being called with all the files in lib/ as args. Since you only reference $1 in your script, it's only printing the first file. You need to escape the wildcard on the command line so it's passed to your script to perform the globbing.

    0 讨论(0)
提交回复
热议问题