shell字符串坏替换

cat*_*ail 6 string shell substitution

我知道这很愚蠢,但我是shell的新手,我真的不知道这里发生了什么.以下是打算在zip文件被提取后获取目录名.因此,如果有效,结果将是这样的

$test.sh helloworld.zip
helloworld
Run Code Online (Sandbox Code Playgroud)

我们来看看test.sh:

#! /bin/sh
length=echo `expr index "$1" .zip`
a=$1    
echo $(a:0:length}
Run Code Online (Sandbox Code Playgroud)

然而,我得到了糟糕的替代,这只是搞砸了.
当我提到'shell'时.我只是在谈论shell而我不知道bash或其他之间的差异.我只是使用ubuntu 10.04并使用终端.我想我正在使用bash.

小智 7

尝试用 bash 运行它。

bash test.sh helloworld.zip

-同样地-

“尝试将第一行更改为#!/bin/bash ”作为评论回答 – @shellter


Jon*_*ler 6

如果您的Shell是的最新版本bash,则该参数扩展符号应该起作用。

在许多其他Shell中,它将不起作用,并且bad substitution错误是Shell表示“您要求参数替换,但对我而言没有意义”。


同样,给定脚本:

#! /bin/sh
length=echo `expr index "$1" .zip`
a=$1    
echo $(a:0:length}
Run Code Online (Sandbox Code Playgroud)

第二行导出变量length,其值echo包含运行产生的命令的值expr index "$1" .zip。它没有分配给length。那应该只是:

length=$(expr index "${1:?}" .zip)
Run Code Online (Sandbox Code Playgroud)

${1:?}如果$1未设置,则表示法会生成错误(如果脚本不带参数调用)。

最后一行应该是:

echo ${a:0:$length}
Run Code Online (Sandbox Code Playgroud)

请注意,如果$1hold filename.zip,则输出expr index $1 .zip为2,因为字母i出现在中的索引2处filename.zip。如果打算获取不带.zip扩展名的文件的基本名称,那么经典的实现方法是:

base=$(basename $1 .zip)
Run Code Online (Sandbox Code Playgroud)

更现代的方式是:

base=${1%.zip}
Run Code Online (Sandbox Code Playgroud)

它们是有区别的; 如果名称是/path/to/filename.zip,经典输出是filename,现代输出是/path/to/filename。您可以通过以下方式获得经典输出:

base=${1%.zip}
base=${base##*/}
Run Code Online (Sandbox Code Playgroud)

或者,在经典版本中,您可以使用以下方法获取路径:

base=$(dirname $1)/$(basename $1 .zip)`.)
Run Code Online (Sandbox Code Playgroud)

如果文件名称可以包含空格,则需要考虑使用双引号,尤其是在的调用basenamedirname

  • 什么是“足够新的版本”?我正在使用 bash 4.2.37,我遇到了这个问题。 (2认同)