неправильная замена строки оболочки

Я новичок в программировании оболочки. Я намерен получить имя каталога после извлечения zip-файла. Заявление о печати это

$test.sh helloworld.zip
helloworld

Давайте посмотрим на test.sh:

#! /bin/sh
length=echo `expr index "$1" .zip`
a=$1    
echo $(a:0:length}

Однако я получил ошибку неправильной замены от компилятора.

И когда я упоминаю о «оболочке». Я просто говорю о оболочке, потому что не знаю разницы между bash и другими. Я просто использую Ubuntu 10.04 и использую терминал. (Я использую bash.)


person cattail    schedule 11.10.2012    source источник
comment
каков ваш аргумент для сценария, то есть значение $ 1? Пожалуйста, отредактируйте эту информацию в своем сообщении выше, а не как ответ на мой комментарий. попробуйте заключить все ссылки на $1 в двойные кавычки, т.е. echo "$1" и т. д. Удачи!   -  person shellter    schedule 11.10.2012
comment
Что вы ожидали от ${a:0} ?   -  person Gilles Quenot    schedule 11.10.2012
comment
попробуйте изменить первую строку на #!/bin/bash. Удачи.   -  person shellter    schedule 11.10.2012
comment
Ого, добавь #! /bin/bash работает. ПОЧЕМУ? В чем разница между использованием #! /bin/bash и #! /бин/ш   -  person cattail    schedule 11.10.2012
comment
Это разные оболочки, которые реализуют разные функции. Даже если /bin/sh является bash, он выполняется так, как если бы использовался --posix, что отключает некоторые функции bash.   -  person jordanm    schedule 11.10.2012
comment
Если вы используете Ubuntu, /bin/sh может быть dash (Debian Almquist Shell), и это очень близко к стандарту POSIX и не поддерживает расширения только для Bash.   -  person Jonathan Leffler    schedule 25.03.2014


Ответы (3)


Если ваша оболочка является достаточно новой версией bash, этот параметр нотация расширения должна работать.

Во многих других оболочках это не будет работать, и ошибка bad substitution — это то, как оболочка говорит: «Вы запросили замену параметра, но для меня это не имеет смысла».


Кроме того, учитывая сценарий:

#! /bin/sh
length=echo `expr index "$1" .zip`
a=$1    
echo $(a:0:length}

Вторая строка экспортирует переменную length со значением echo для команды, сгенерированной запуском expr index "$1" .zip. Он не назначается length. Это должно быть просто:

length=$(expr index "${1:?}" .zip)

где нотация ${1:?} генерирует ошибку, если $1 не установлено (если скрипт вызывается без аргументов).

Последняя строка должна быть:

echo ${a:0:$length}

Обратите внимание, что если $1 содержит filename.zip, выход expr index $1 .zip равен 2, потому что буква i появляется в индексе 2 в filename.zip. Если намерение состоит в том, чтобы получить базовое имя файла без расширения .zip, то классический способ сделать это:

base=$(basename $1 .zip)

и более современный способ:

base=${1%.zip}

Есть разница; если имя /path/to/filename.zip, классический вывод — filename, а современный — /path/to/filename. Вы можете получить классический вывод с помощью:

base=${1%.zip}
base=${base##*/}

Или, в классической версии, вы можете получить путь с помощью:

base=$(dirname $1)/$(basename $1 .zip)`.)

Если имена файлов могут содержать пробелы, вам нужно подумать об использовании двойных кавычек, особенно при вызове basename и dirname.

person Jonathan Leffler    schedule 11.10.2012
comment
Что такое достаточно свежая версия? Я работаю с bash 4.2.37 и столкнулся с этой проблемой. - person Simon; 25.03.2014
comment
@Simon: у меня это работает с Bash 3.2.51 (поставляется с Mac OS X 10.9.2 Mavericks). Он также работает с Bash 4.2.25 (поставляется с Ubuntu 12.04). Например: AZ=abcdefghijklmnopqrstuvwxyz; echo ${AZ:10:10} дает klmnopqrst в обеих системах. Кроме того, он работает нормально, работает ли Bash как bash или как sh. Итак, вам нужно уточнить, что именно вы делаете, в соответствии с примером, который я только что привел. Обратите внимание, что оба значения должны быть числами. Вы могли бы написать: length=10 и echo ${AZ:10:$length}, но второе $ имеет решающее значение в этом обозначении. - person Jonathan Leffler; 25.03.2014
comment
Спасибо за быстрый ответ. На самом деле AZ=abcdefghijklmnopqrstuvwxyz; echo ${AZ:10:10} дает мне Bad substitution (Bash 4.2.37 - Debian 7.4). Я думаю, мне нужно копнуть глубже. - person Simon; 25.03.2014
comment
@Simon: вот это любопытное положение дел. Я думаю, вам нужно будет отследить, что есть в 4.2.37 по сравнению с 4.2.25 или что-то в этом роде (без гарантии, что ваш «.25» такой же, как «мой»). Bash 4.3 был выпущен Gnu 26 февраля 2014 г. (4.2 от 13 февраля 2011 г.). ). Может, попробовать построить? В противном случае у вас может быть ошибка регрессии на ваших руках. (Я только что собрал Bash 4.3 на Mac OS X 10.9.2, добавляя этот комментарий — после завершения загрузки это заняло пару минут — и AZ-тест работает на нем чисто.) - person Jonathan Leffler; 25.03.2014
comment
@Simon - пять лет спустя мне приходит в голову, что вы, возможно, используете (использовали) dash вместо bash. - person Jonathan Leffler; 13.04.2019

Попробуйте запустить его с помощью bash.

bash test.sh helloworld.zip

-так же-

«попробуйте изменить первую строку на #!/bin/bash», как ответил на комментарий — @shellter

person Brian Davis    schedule 03.10.2018
comment
я использовал sh test.sh и обновил bash test.sh. Спасибо - person Anmol Parida; 17.05.2021

Попробуйте это в bash :

echo $1
len=$(wc -c <<< "$1")
a="${1}.zip"
echo ${a:0:$len}

Адаптируйте его под свои нужды.

person Gilles Quenot    schedule 11.10.2012