Shell script: проверить имя каталога и преобразовать в нижний регистр

Я хочу, чтобы мой bash script проверял имя каталога, в котором он запущен. Что-то вроде:

#!/bin/bash

path=eval 'pwd'

dirname=eval 'basename $path'

Но это не работает: я получаю

./foo.sh: line 5: basename $path: command not found

Как я могу это исправить? Кроме того, как только я получаю dirname, чтобы содержать правильное имя dirname, я хотел бы преобразовать его в нижний регистр, чтобы проверить его. Я могу сделать это в командной строке с awk:

echo $dirname | awk '{print tolower($0)}'

но как я могу вернуть возвращаемое значение в переменную? Заранее спасибо,

С наилучшими пожеланиями

Серхио

Ответ 1

Почему бы не использовать:

#!/bin/bash

path=`pwd`
dirname=`basename $path | awk '{print tolower($0)}'`

Или если вы хотите сделать это как один лайнер:

dirname=`pwd | xargs basename | awk '{print tolower($0)}'`

Ответ 2

Вы можете переписать его на

dirname=eval "basename $path"

При использовании одиночных кавычек вы не получите расширение оболочки, но хотите, чтобы $path расширялся.

Кстати: я бы предложил использовать

path=$(basename $path)

Это более универсальный и более читаемый, если вы делаете что-то вроде

path=$(basename $(pwd))

или получить строчный результат

path=$(basename $(pwd) | awk '{print tolower($0)}')

или

path=$(basename $(pwd) | tr 'A-Z' 'a-z' )

Ответ 3

Форма

x=y cmd

означает временно установить переменную среды x в значение y, а затем запустить cmd, как интерпретируются эти строки:

path=eval 'pwd'
dirname=eval 'basename $path'

То есть, они не делают то, что вы, кажется, ожидаете вообще, вместо этого устанавливаете переменную среды для литерального значения eval, а затем запускаете (или не можете найти) команду. Как говорили другие, способ интерполяции результатов команды в строку состоит в том, чтобы поместить ее внутри $(...) (предпочтительно) или `...` (наследие). И, как правило, безопаснее обернуть их в двойные кавычки (так как безопаснее обернуть любую интерполированную ссылку в кавычки).

path="$(pwd)"
dirname="$(basename "$path")"

(Технически, в этом случае внешние кавычки не являются строго необходимыми. Однако я бы сказал, что это хорошая привычка иметь.)

Ответ 4

B=$(echo "Some text that has CAPITAL letters " | awk '{print tolower($0)}')

Ответ 5

eval выполняет команду, переданную ему, но возвращает код состояния выхода из командной строки, поэтому вы не можете использовать его в операторе set. Путь к тому, чтобы вставлять команду в оператор набора, либо использовать правильные одинарные кавычки, либо $()

Итак, script будет выглядеть так:

#!/bin/bash

curr_path=$(pwd)
echo $curr_path
curr_dir=$(basename $curr_path)
echo $curr_dir
echo $curr_dir | awk '{print tolower($0)}'

Ответ 6

Ваш код не работает, потому что вы используете одиночные кавычки, а не двойные кавычки. Одиночные кавычки предотвращают расширение переменных, поэтому $path не расширяется в путь, который вы хотите использовать, и принимается как есть, так как он был строкой.

Ваш вызов awk не будет работать по той же причине.

Хотя вы можете решить проблему, заменяя одинарные кавычки двойными кавычками, например:

#!/bin/bash

path=eval "pwd"
dirname=eval "basename $path"

Вместо этого я предлагаю использовать более серьезные акценты (). There no reason to use eval`). Кроме того, вы можете использовать его для сбора возвращаемого значения, которое вас интересует:

#!/bin/bash

path=`pwd`
dirname=`basename $path`
variable=`echo $dirname | awk "{print tolower($0)}"`

Ответ 7

Вот отрывок из моего ответа на Какой независимый от платформы способ найти директорию оболочки, исполняемую в оболочке script?, которая сама по себе полностью отвечает на ваш вопрос в сторону из нижней части, что, на мой взгляд, было должным образом рассмотрено много раз в других ответах здесь.

Что единственное в моем ответе - то, что когда я пытался написать его для другого вопроса, я столкнулся с вашей точной проблемой - , как сохранить результаты функции в переменной? Ну, как вы можете см. с некоторой помощью, я попал в довольно простое и очень мощное решение:

Я могу передать функцию своего рода переменной мессенджера и разыменовать любое явное использование результирующего аргумента функции $1 name с eval по мере необходимости, а после завершения процедуры функции я использую eval и обратную косую черту цитируя трюк, чтобы присвоить переменной моего мессенджера значение, которое я хочу, даже не зная его имени.

В полном раскрытии, хотя это было решением моей проблемы, это было не каким-либо образом мое решение. Я имел несколько случаев, чтобы посетить там раньше, но некоторые из его описаний, хотя, возможно, блестящие, немного из моей лиги, и поэтому я думал, что другие могут принести пользу, если включить мою собственную версию того, как это работает в предыдущем абзаце. Хотя, конечно, было очень просто понять, как только я это сделал, особенно для этого, мне пришлось долго и долго думать, как это может сработать. В любом случае, вы можете найти это и многое другое в Rich sh tricks, и я также вычитал соответствующую часть его страницы ниже моего собственного отклика ответа.

... ВЫПИСКА: ...

Хотя не строго POSIX, realpath является основным приложением GNU с 2012 года. Полное раскрытие: никогда не слышал об этом, прежде чем я заметил его в TOC info coreutils и сразу подумал о [связанном] вопросе, но используя следующую функцию, как показано, должен быть надежно (скоро POSIXLY?) И, надеюсь, эффективно предоставить своему вызывающему абоненту абсолютно исходный $0:

% _abs_0() { 
> o1="${1%%/*}"; ${o1:="${1}"}; ${o1:=`realpath "${1}"`}; eval "$1=\${o1}"; 
> }  
% _abs_0 ${abs0:="${0}"} ; printf %s\\n "${abs0}"
/no/more/dots/in/your/path2.sh

EDIT: Возможно, стоит отметить, что в этом решении используется расширение параметра POSIX, чтобы сначала проверить, на самом деле требуется расширение и разрешение вообще, прежде чем пытаться это сделать. Это должно вернуть абсолютно sourced $0 через переменную messenger (с заметным исключением, что она сохранит symlinks) как эффективно, как я мог себе представить, что это можно сделать , является ли путь уже абсолютным. ...

( незначительное редактирование: перед тем, как найти realpath в документах, я по крайней мере уменьшил мою версию [версии ниже], чтобы не зависеть от поля времени [как это было в первая команда ps], но, честное предупреждение, после тестирования некоторые из них менее убедительны. ps полностью надежен в своем расширении пропускной способности)

С другой стороны, вы можете сделать это:

ps ww -fp $$ | grep -Eo '/[^:]*'"${0#*/}"

eval "abs0=${`ps ww -fp $$ | grep -Eo ' /'`#?}"

... И от Rich sh tricks: ...

Возвращаемые строки из функции оболочки

Как видно из приведенной выше ошибки подстановки команд, stdout не является хорошим средством для функций оболочки, чтобы возвращать строки их вызывающему абоненту, если выход не находится в формате, где конечные символы новой строки несущественны. Конечно, такая практика неприемлема для функций, предназначенных для обработки произвольных строк. Итак, что можно сделать?

Попробуйте следующее:

func () {
body here
eval "$1=\${foo}"
}

Конечно, ${foo} можно заменить любой подстановкой. Ключевым трюком здесь является линия eval и использование экранирования. "$1" расширяется, когда аргумент eval создается главным парсером команды. Но "${foo}" не расширяется на этом этапе, поскольку цитируется "$". Вместо этого его расширение, когда eval оценивает его аргумент. Если неясно, почему это важно, подумайте о том, как это будет плохо:

foo='hello ; rm -rf /'
dest=bar
eval "$dest=$foo"

Но, конечно, следующая версия совершенно безопасна:

foo='hello ; rm -rf /'
dest=bar
eval "$dest=\$foo"

Обратите внимание, что в исходном примере "$1" использовался, чтобы позволить вызывающему лицу передать имя целевой переменной в качестве аргумента функции. Если вашей функции необходимо использовать команду shift, например, чтобы обрабатывать оставшиеся аргументы как "[email protected]", тогда может быть полезно сохранить значение "$1" во временной переменной в начале функции.