Bash :将通配符作为 shell 脚本的参数并能够扩展它
Bash : Taking a wildcard as argument of a shell script and being able to expand it
我遇到了一个乍一看很容易的具体问题。
如果我在 bash shell 上键入对应于不同文件的通配符:
$ myfile=probe_*.txt
并在 :
之后执行
$ echo $myfile
我得到了与通配符匹配的所有文件的列表,即:
$ probe_GCph.txt probe_GCsp.txt probe_GCsp_WL_GCph.txt probe_GCsp_XC.txt probe_GCsp_XC_WL_GCph.txt probe_WL.tx
但是现在,我想把通配符probe_*.txt
作为参数</code>变成一个函数。</p>
<p>目前,如果我在 bash 函数中执行:</p>
<pre><code>function multiple_files { myfile=
echo
echo
echo $myfile
}
然后,在下面的执行:
$ multiple_files . $myfile dir/
然后我只得到第一个文件名 probe_GCph.txt
,它是在 bash 函数的定义中为第三个 echo (echo $myfile
) 打印的。
如何将文件的通配符名称作为参数(此处为 $2)传递,然后能够将其展开以列出 bash 函数中对应的所有文件名?
仅考虑第一个扩展文件 probe_GCph.txt
的参数 $2 与不扩展它而将通配符作为参数 $2 传递之间似乎存在冲突。
如何规避这个问题?
双引号避免扩展 shell glob,但仍允许 shell 变量替换。值得注意的是,单引号既可以防止 glob(或类似扩展的通配符)也可以防止变量插值。
长话短说:
这样调用你的函数:
multiple_files . "$myfile" dir/
要在函数内部传递通配符,您需要转义特殊字符或在引号中包含通配符序列。
$ ls
f1 f2 f3
$ function multiple_files { myfile=; echo ; echo ; echo $myfile;}
$ multiple_files '*' f\*
f1 f2 f3
f1 f2 f3
f1 f2 f3
如果您不转义通配符,它会在调用函数之前展开
$ multiple_files f*
f1
f2
f2
要在函数内打印通配符,您还需要在引号中包含变量。 eval
也有一些技巧:
$ function multiple_files { myfile=; echo ; eval echo ""; echo ""; echo "$myfile"; eval echo "$myfile";}
$ multiple_files '*' f\*
f1 f2 f3
f1 f2 f3
f*
f*
f1 f2 f3
编写您的函数以接受多个参数而不是一个。这就是大多数其他工具的工作方式(cp/mv/ls/grep/sed 仅举几例):
multiple_files() {
first=""
last="${@: -1}"
files=( "${@:2:$#-2}" )
echo "The first thing was $first"
echo "The last thing was $last"
for file in "${files[@]}"
do
echo "One of the files is $file"
done
}
multiple_files . probe_*.txt dir/
这导致:
The first thing was .
The last thing was dir/
One of the files is probe_GCph.txt
One of the files is probe_GCsp.txt
One of the files is probe_GCsp_WL_GCph.txt
One of the files is probe_GCsp_XC.txt
如果您确实需要模式本身,或者如果您想接受多个模式并将它们分开,您可能需要按照其他答案中的描述引用 glob。
我遇到了一个乍一看很容易的具体问题。
如果我在 bash shell 上键入对应于不同文件的通配符:
$ myfile=probe_*.txt
并在 :
之后执行$ echo $myfile
我得到了与通配符匹配的所有文件的列表,即:
$ probe_GCph.txt probe_GCsp.txt probe_GCsp_WL_GCph.txt probe_GCsp_XC.txt probe_GCsp_XC_WL_GCph.txt probe_WL.tx
但是现在,我想把通配符probe_*.txt
作为参数</code>变成一个函数。</p>
<p>目前,如果我在 bash 函数中执行:</p>
<pre><code>function multiple_files { myfile=
echo
echo
echo $myfile
}
然后,在下面的执行:
$ multiple_files . $myfile dir/
然后我只得到第一个文件名 probe_GCph.txt
,它是在 bash 函数的定义中为第三个 echo (echo $myfile
) 打印的。
如何将文件的通配符名称作为参数(此处为 $2)传递,然后能够将其展开以列出 bash 函数中对应的所有文件名?
仅考虑第一个扩展文件 probe_GCph.txt
的参数 $2 与不扩展它而将通配符作为参数 $2 传递之间似乎存在冲突。
如何规避这个问题?
双引号避免扩展 shell glob,但仍允许 shell 变量替换。值得注意的是,单引号既可以防止 glob(或类似扩展的通配符)也可以防止变量插值。
长话短说:
这样调用你的函数:
multiple_files . "$myfile" dir/
要在函数内部传递通配符,您需要转义特殊字符或在引号中包含通配符序列。
$ ls
f1 f2 f3
$ function multiple_files { myfile=; echo ; echo ; echo $myfile;}
$ multiple_files '*' f\*
f1 f2 f3
f1 f2 f3
f1 f2 f3
如果您不转义通配符,它会在调用函数之前展开
$ multiple_files f*
f1
f2
f2
要在函数内打印通配符,您还需要在引号中包含变量。 eval
也有一些技巧:
$ function multiple_files { myfile=; echo ; eval echo ""; echo ""; echo "$myfile"; eval echo "$myfile";}
$ multiple_files '*' f\*
f1 f2 f3
f1 f2 f3
f*
f*
f1 f2 f3
编写您的函数以接受多个参数而不是一个。这就是大多数其他工具的工作方式(cp/mv/ls/grep/sed 仅举几例):
multiple_files() {
first=""
last="${@: -1}"
files=( "${@:2:$#-2}" )
echo "The first thing was $first"
echo "The last thing was $last"
for file in "${files[@]}"
do
echo "One of the files is $file"
done
}
multiple_files . probe_*.txt dir/
这导致:
The first thing was .
The last thing was dir/
One of the files is probe_GCph.txt
One of the files is probe_GCsp.txt
One of the files is probe_GCsp_WL_GCph.txt
One of the files is probe_GCsp_XC.txt
如果您确实需要模式本身,或者如果您想接受多个模式并将它们分开,您可能需要按照其他答案中的描述引用 glob。