【问题标题】:Passing and parsing file matches传递和解析文件匹配
【发布时间】:2023-12-06 12:17:02
【问题描述】:

我想传递与某些通配符或正则表达式匹配的文件。以这种方式将文件名传递给脚本是否可以接受?

mse -s /media/hagbard/hc1/a1-chaos/amvib/A*

-s 是一个选项,但 /media/hag/hc1/a1-chaos/amvib/A* 将构成多个文件名,一个接一个。

目前我正在使用以下内容解析参数,但必须注意 -s 选项,因此它不会只捕获一个值。 这可能是有道理的,除非有很多文件。如果要处理的 args 文件太多,我需要能够传递和解释某种形式的通配符或正则表达式,这也需要适当的选项和相关的解析方案。

 #!/bin/bash
 IFSPREV="$IFS"
 IFS="="
 set -- $*

 IFS="$IFSPREV"  # Set original IFS

 local iarg=0
 local narg="$#"
 while (( narg > 0 )); do

   opt="$1"
   iarg=$(( iarg + 1 ))

   case $opt in
     ("-s"|"--src"|"--source")  src="$2"  ; shift 2 ;;
     ("-d"|"--dst"|"--destin")  dst="$2"  ; shift 2 ;;
     ("--")  shift 1 ; break ;;
     (-*)  printf '%s\n' "Unknown option: $1" ; shift 1 ;;
     (*) break ;;
   esac

 done

 for name in "$src"; do
   rsync -av --update "$src" "$dst"
 done

【问题讨论】:

  • 请添加合适的 shebang (#!/bin/bash),然后将您的脚本粘贴到 shellcheck.net 并尝试实施那里提出的建议。

标签: bash arguments wildcard glob


【解决方案1】:

首先,不要使用一个元素,而是使用 bash 数组。

srcs=()
...
printf "You passed filenames:\n"
printf "   %s\n" "${srcs[@]}"

有很多解决方案。最好实现单个标志并从零分隔文件或仅位置参数读取。

  1. 不是添加一个元素,而是将它们添加到一个数组中。

    ("-s"|"--src"|"--source") srcs+=("$2"); shift 2 ;;
    

并要求用户在每个文件名前添加-s

args=(); for i in /media/hagbard/hc1/a1-chaos/amvib/A*; do args+=(-s "$i"); done
mse "${args[@]}"
  1. 要求用户传递一个通配符(或正则表达式)并在您这边展开。

     # ex. find -name '*.txt'
     # or git ls-files '*.txt'
     # BAD code - does not handle whitespaces in filenames
     ("-g"|"--srcglob"|"--sourceglob") srcs+=($(compgen -G "$2")); shift 2 ;;
    

你会这样做,注意引号:

 ./mse '/media/hagbard/hc1/a1-chaos/amvib/A*'
  1. 允许用户从文件中传递。

     # see rsync --from0 --from-file documentation of these flags
     (-0|--from0) mapfileargs=(-d '') ;;
     (--from-file) readarray -t "${mapfileargs[@]}" srcs < <(cat "$2"); ;;
     # see grep -z -Z -f flags documentation
    

你会这样做:

printf "%s\0" /media/hagbard/hc1/a1-chaos/amvib/A* | ./mse --from0 --files-from=-
  1. 在选项之后提供所有参数作为位置参数。

   ("--")  shift 1 ; break ;;
    ...
done

srcs=("$@")

这是最简单的 - 只需使用:

./mse /media/hagbard/hc1/a1-chaos/amvib/A*

【讨论】: