Как установить переменную на вывод команды в Bash?

У меня довольно простой скрипт, который выглядит примерно так:

#!/bin/bash VAR1="$1" MOREF='sudo run command against $VAR1 | grep name | cut -c7-' echo $MOREF 

Когда я запускаю этот скрипт из командной строки и передаю ему аргументы, я не получаю никакого вывода. Однако, когда я запускаю команды, содержащиеся в переменной $MOREF , я могу получить выход.

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

В дополнение к обратным выводам вы можете использовать $() , который мне легче читать, и позволяет вложенность.

 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" 

Как они уже указывали вам, вы должны использовать «обратные сигналы».

Альтернативная предложенная $(command) работает, и ее также легче читать, но обратите внимание, что она действительна только с shellми bash или korn (и shellми, полученными из них), поэтому, если ваши скрипты должны быть действительно переносимыми на разных Unix систем, вы должны предпочесть старую обратную запись.

Я знаю три способа:

1) Функции подходят для таких задач:

 func (){ ls -l } 

Вызовите его, произнеся func

2) Еще одно подходящее решение может быть оценено:

 var="ls -l" eval $var 

3) Третий использует прямые переменные:

 var=$(ls -l) OR var=`ls -l` 

вы можете получить выход третьего решения в хорошем смысле:

 echo "$var" 

а также отвратительно:

 echo $var 

Некоторые трюки bash, которые я использую для установки переменных из команд

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  

Все трубы ( | ) подразумевают вилки. Там, где должен выполняться другой процесс, доступ к дискам, вызовам библиотек и т. Д.

Поэтому использование sed для образца ограничивает subprocess только одной вилкой :

 shell=$(sed  

И с багизмами :

Но для многих действий, в основном на небольших файлах, bash мог выполнить эту работу сам:

 while IFS=: read -a line ; do [ "$line" = "$USER" ] && shell=${line[6]} done  

или

 while IFS=: read loginname encpass uid gid fullname home shell;do [ "$loginname" = "$USER" ] && break done  

Далее о переменном расщеплении ...

Посмотрите на мой ответ: Как разбить строку на разделителе в 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 

(конечно, 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  

Оттуда, если вы хотите закончить один из фоновых процессов, вам просто нужно закрыть его 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 закрываются при завершении основного процесса.

Просто быть другим:

 MOREF=$(sudo run command against $VAR1 | grep name | cut -c7-) 

Если вы хотите сделать это с помощью multiline / multiple command / s, вы можете сделать это:

 output=$( bash < 

Или:

 output=$( #multiline/multiple command/s ) 

Пример:

 #!/bin/bash output="$( bash < 

Вывод:

 first second third 

Используя heredoc, вы можете легко упростить ситуацию, разбив свой длинный однострочный код на многострочный. Другой пример:

 output="$( ssh -p $port [email protected]$domain < 

При настройке переменной убедитесь, что у вас нет пробелов до и / или после знака = . Буквально потратил час, пытаясь понять это, пытаясь найти всевозможные решения! Это не круто.

Верный:

 WTFF=`echo "stuff"` echo "Example: $WTFF" 

Сбой с ошибкой: (материал: не найден или похоже)

 WTFF= `echo "stuff"` echo "Example: $WTFF" 

Вы можете использовать обратные тики (также известные как ударные могилы) или $() . Вроде как-

 OUTPUT=$(x+2); OUTPUT=`x+2`; 

Оба имеют тот же эффект. Но OUTPUT = $ (x + 2) является более читаемым и последним.

Это еще один способ, который можно использовать с некоторыми текстовыми редакторами, которые не могут правильно выделить каждый сложный код, который вы создаете.

 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 

Вы должны использовать либо

$(command-here)

или

 `command-here` 

пример

 #!/bin/bash VAR1="$1" VAR2="$2" MOREF="$(sudo run command against "$VAR1" | grep name | cut -c7-)" echo "$MOREF" 

Вот еще два способа:

Пожалуйста, имейте в виду, что пространство очень важно в bash . Итак, если вы хотите, чтобы ваша команда запускалась, используйте как не добавляя больше пробелов.

  1. следующий присваивает harshil L, а затем печатает его

     L=$"harshil" echo "$L" 
  2. следующий присваивает вывод команды tr в L2. tr работает с другой переменной L1.

     L2=$(echo "$L1" | tr [:upper:] [:lower:]) 
  • Разница между одиночными и двойными кавычками в Bash
  • Bash: ограничить количество одновременных заданий?
  • Случайное число из диапазона в сценарии Bash
  • $$ в скрипте vs $$ в подоболочке
  • пример переполнения буфера из книги Art of Exploitation
  • Как сохранить стандартную ошибку в переменной в сценарии Bash
  • Что рекурсивно распространяется на все файлы в текущем каталоге?
  • Как использовать обратные или отрицательные подстановочные знаки при сопоставлении шаблонов в оболочке unix / linux?
  • Как проверить, установлена ​​ли переменная в Bash?
  • Получить только имя файла из пути в сценарии Bash
  • Как команда сортировки UNIX может сортировать очень большой файл?
  • Давайте будем гением компьютера.