У меня довольно простой скрипт, который выглядит примерно так:
#!/bin/bash
VAR1="$1"
MOREF='sudo run command against $VAR1 | grep name | cut -c7-'
echo $MOREF
Когда я запускаю этот скрипт из командной строки и передаю ему аргументы, я не получаю никакого вывода. Однако, когда я запускаю команды, содержащиеся в переменной $MOREF
, я могу получить выход.
Я хотел бы знать, как можно взять результаты команды, которая должна выполняться в скрипте, сохранить его в переменной и затем выводить эту переменную на экран?
В дополнение к backticks (`command`
) вы можете использовать $(command)
, которую мне легче читать, и позволяет вложенность.
OUTPUT="$(ls -1)"
echo "${OUTPUT}"
Цитирование ("
) имеет значение для сохранения многострочных значений.
Обновление (2018): правильный путь
$(sudo run command)
Вы используете неправильный апостроф. Вам нужно '
не '
. Этот символ называется "backticks" (или "серьезным акцентом").
Как это:
#!/bin/bash
VAR1="$1"
VAR2="$2"
MOREF='sudo run command against "$VAR1" | grep name | cut -c7-'
echo "$MOREF"
echo
.
Как они уже указывали вам, вы должны использовать "обратные метки".
Предлагаемая альтернатива $(command)
также работает, и ее также легче читать,
но обратите внимание, что он действителен только с bash или оболочками korn (и оболочками, полученными из них),
поэтому, если ваши скрипты должны быть действительно переносимыми в разных Unix-системах, вам следует предпочесть старые обозначения backticks.
$()
полностью совместим с POSIX sh, как было стандартизировано более двух десятилетий назад.
Я знаю три способа сделать:
1) Функции подходят для таких задач:
func (){
ls -l
}
Вызовите его, сказав func
2) Еще одно подходящее решение может быть оценено:
var="ls -l"
eval $var
3) Третий использует прямые переменные:
var=$(ls -l)
OR
var=`ls -l`
вы можете получить выход третьего решения в хорошем смысле:
echo "$var"
а также отвратительно:
echo $var
"$var"
хорош, а $var
неприятен?
2nd Edit 2018-02-12: Добавляя особый путь, см. В самом низу этого!
2018-01-25 Edit: добавьте функцию образца (для заполнения vars о дисках)
myPi='echo '4*a(1)' | bc -l'
echo $myPi
3.14159265358979323844
Поскольку вложенность может стать тяжелой, для этой
myPi=$(bc -l <<<'4*a(1)')
Вложенный образец:
SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted
1480656334
df -k /
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/dm-0 999320 529020 401488 57% /
Если я просто хочу Использованное значение:
array=($(df -k /))
вы можете увидеть переменную массива:
declare -p array
declare -a array='([0]="Filesystem" [1]="1K-blocks" [2]="Used" [3]="Available" [
4]="Use%" [5]="Mounted" [6]="on" [7]="/dev/dm-0" [8]="999320" [9]="529020" [10]=
"401488" [11]="57%" [12]="/")'
Затем:
echo ${array[9]}
529020
Но я предпочитаю это:
{ read foo ; read filesystem size used avail prct mountpoint ; } < <(df -k /)
echo $used
529020
1st read foo
просто пропустит строку заголовка (переменная $foo
будет содержать что-то вроде Filesystem 1K-blocks Used Available Use% Mounted on
)
#!/bin/bash
declare free=0 total=0 used=0
getDiskStat() {
local foo
{
read foo
read foo total used free foo
} < <(
df -k ${1:-/}
)
}
getDiskStat $1
echo $total $used $free
Nota: строка declare
не требуется, просто для удобства чтения.
sudo cmd | grep... | cut...
sudo cmd | grep... | cut...
shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash
(Пожалуйста, избегайте бесполезной cat
! Так что это всего лишь 1 вилка меньше:
shell=$(grep $USER </etc/passwd | cut -d : -f 7)
Все трубы (|
) подразумевают вилки. Там, где должен выполняться другой процесс, доступ к дискам, вызовам библиотек и т.д.
Поэтому использование sed
для образца ограничивает подпроцесс только одной вилкой:
shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell
Но для многих действий, в основном на небольших файлах, bash мог выполнить эту работу сам:
while IFS=: read -a line ; do
[ "$line" = "$USER" ] && shell=${line[6]}
done </etc/passwd
echo $shell
/bin/bash
или
while IFS=: read loginname encpass uid gid fullname home shell;do
[ "$loginname" = "$USER" ] && break
done </etc/passwd
echo $shell $loginname ...
Посмотрите на мой ответ: Как разбить строку на разделителе в Bash?
2-е изм. Редактирование 2018-02-12: Чтобы предотвратить появление нескольких вилок
myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")
или
myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)
И поскольку date
и bc
могут работать по строкам:
bc -l <<<$'3*4\n5*6'
12
30
date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288
Мы могли бы использовать длительный фоновый процесс для повторной работы, без необходимости запуска новой вилки для каждого запроса:
mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc
(конечно, FD 5
и 6
должны быть неиспользованными!)... Оттуда вы можете использовать этот процесс:
echo "3*4" >&5
read -u 6 foo
echo $foo
12
echo >&5 "pi=4*a(1)"
echo >&5 "2*pi*12"
read -u 6 foo
echo $foo
75.39822368615503772256
newConnector
Вы можете найти мою функцию newConnector
на GitHub.Com или на моем собственном сайте (Nota on github, есть два файла, на моем сайте, функция и демонстрация включены в 1 файл, который может быть использован для использования или просто запускаться для демонстрации)
Образец:
. shell_connector.sh
tty
/dev/pts/20
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30745 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
newConnector /usr/bin/bc "-l" '3*4' 12
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30944 pts/20 S 0:00 \_ /usr/bin/bc -l
30952 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
declare -p PI
bash: declare: PI: not found
myBc '4*a(1)' PI
declare -p PI
declare -- PI="3.14159265358979323844"
Функция myBc
позволяет использовать фоновое задание с простым синтаксисом и для даты:
newConnector /bin/date '-f - +%s' @0 0
myDate '2000-01-01'
946681200
myDate "$(ps ho lstart 1)" boottime
myDate now now ; read utm idl </proc/uptime
myBc "$now-$boottime" uptime
printf "%s\n" ${utm%%.*} $uptime
42134906
42134906
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
29019 pts/20 Ss 0:00 bash
30944 pts/20 S 0:00 \_ /usr/bin/bc -l
32615 pts/20 S 0:00 \_ /bin/date -f - +%s
3162 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
Оттуда, если вы хотите закончить один из фоновых процессов, вам просто нужно закрыть его fd:
eval "exec $DATEOUT>&-"
eval "exec $DATEIN>&-"
ps --tty pts/20 fw
PID TTY STAT TIME COMMAND
4936 pts/20 Ss 0:00 bash
5256 pts/20 S 0:00 \_ /usr/bin/bc -l
6358 pts/20 R+ 0:00 \_ ps --tty pts/20 fw
которые не нужны, потому что все fd закрываются при завершении основного процесса.
EXISTING_CONTAINER=$(docker ps -a | grep "$(echo $CONTAINER_NAME)")
было заявлением, которое я искал.
echo
; Вы хотите просто grep "$CONTAINER_NAME"
Просто чтобы быть другим:
MOREF=$(sudo run command against $VAR1 | grep name | cut -c7-)
При настройке переменной убедитесь, что у вас есть НЕТ пространства до и/или после знака =. Буквально потратил час, пытаясь понять это, пытаясь найти всевозможные решения! Это не круто.
Правильно:
WTFF=`echo "stuff"`
echo "Example: $WTFF"
Сбой с ошибкой: (материал: не найден или подобный)
WTFF= `echo "stuff"`
echo "Example: $WTFF"
var=value somecommand
запускает somecommand
с var
в своей среде, имеющей значение value
. Таким образом, var= somecommand
экспортирует var
в среде somecommand
с пустым (нулевым байтом) значением.
Если вы хотите сделать это с помощью multiline/multiple command/s, вы можете сделать это:
output=$( bash <<EOF
#multiline/multiple command/s
EOF
)
Или:
output=$(
#multiline/multiple command/s
)
Пример:
#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"
Вывод:
first
second
third
Используя heredoc, вы можете легко упростить ситуацию, разбив свой длинный однострочный код на многострочный. Другой пример:
output="$( ssh -p $port $user@$domain <<EOF
#breakdown your long ssh command into multiline here.
EOF
)"
bash
внутри подстановки команд? Вы уже создаете подоболочку самой подстановкой команд. Если вы хотите поместить несколько команд, просто разделите их символом новой строки или точкой с запятой. output=$(echo first; echo second; ...)
Вы можете использовать обратные тики (также называемые акцентными могилами) или $()
.
Например, как
OUTPUT=$(x+2);
OUTPUT=`x+2`;
Оба имеют тот же эффект. Но OUTPUT = $(x + 2) является более читаемым и последним.
bash: x+2: command not found
Вы должны использовать либо
$(command-here)
или
'command-here'
пример
#!/bin/bash
VAR1="$1"
VAR2="$2"
MOREF="$(sudo run command against "$VAR1" | grep name | cut -c7-)"
echo "$MOREF"
$()
намного лучше, чем обратные помехи. См. В чем преимущество использования $ () вместо обратных кавычек в сценариях оболочки?
Это другой способ, который можно использовать с некоторыми текстовыми редакторами, которые не могут правильно выделить каждый сложный код, который вы создаете.
read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"
Некоторые могут найти это полезным.
Целочисленные значения в подстановке переменных, где трюк использует $(())
двойные скобки:
N=3
M=3
COUNT=$N-1
ARR[0]=3
ARR[1]=2
ARR[2]=4
ARR[3]=1
while (( COUNT < ${#ARR[@]} ))
do
ARR[$COUNT]=$((ARR[COUNT]*M))
(( COUNT=$COUNT+$N ))
done
for ((...))
как лучшее совпадение для переменной цикла). Кроме того, вы не должны использовать верхний регистр для ваших личных переменных.
Вот еще два способа:
Имейте в виду, что пространство очень важно в bash. Итак, если вы хотите, чтобы ваша команда запускалась, используйте как не добавляя больше пробелов.
следующий присваивает harshil L, а затем печатает его
L=$"harshil"
echo "$L"
следующий присваивает вывод команды tr
в L2. tr
работает с другой переменной L1.
L2=$(echo "$L1" | tr [:upper:] [:lower:])
$"..."
вероятно, не делает то, что вы думаете . 2. Это уже дано в ответе Энди Лестера.
echo ${L1,,}
для нижнего регистра или echo ${L1^^}
для нижнего регистра.