Linux присвоить значение команды переменной

How do I set a variable to the output of a command in Bash?

When I run this script from the command line and pass it the arguments, I am not getting any output. However, when I run the commands contained within the $MOREF variable, I am able to get output. How can one take the results of a command that needs to be run within a script, save it to a variable, and then output that variable on the screen?

As an aside, all-caps variables are defined by POSIX for variable names with meaning to the operating system or shell itself, whereas names with at least one lowercase character are reserved for application use. Thus, consider using lowercase names for your own shell variables to avoid unintended conflicts (keeping in mind that setting a shell variable will overwrite any like-named environment variable).

As an aside, capturing output into a variable just so you can then echo the variable is a useless use of echo , and a useless use of variables.

As a further aside, storing output in variables is often unnecessary. For small, short strings you will need to reference multiple times in your program, this is completely fine, and exactly the way to go; but for processing any nontrivial amounts of data, you want to reshape your process into a pipeline, or use a temporary file.

Variation: «I know how to use variable=$(command) but I think «$string» is a valid command «; stackoverflow.com/questions/37194795/…

16 Answers 16

In addition to backticks `command` , command substitution can be done with $(command) or «$(command)» , which I find easier to read, and allows for nesting.

OUTPUT=$(ls -1) echo "$" MULTILINE=$(ls \ -1) echo "$" 

Quoting ( » ) does matter to preserve multi-line variable values; it is optional on the right-hand side of an assignment, as word splitting is not performed, so OUTPUT=$(ls -1) would work fine.

@timhc22, the curly braces are irrelevant; it’s only the quotes that are important re: whether expansion results are string-split and glob-expanded before being passed to the echo command.

Curly braces can be used when the variable is immediately followed by more characters which could be interpreted as part of the variable name. e.g. $foo . They are also required when performing inline string operations on the variable, such as $

If you’re going to use an apostrophe, you need ` , not ‘ . This character is called «backticks» (or «grave accent»):

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

The backtick syntax is obsolescent, and you really need to put double quotes around the variable interpolation in the echo .

I would add that you have to be careful with the spaces around ‘=’ in the assignment above. You shouln’t have any spaces there, otherwise you’ll get an incorrect assignment

Читайте также:  Enable wifi on kali linux

tripleeee’s comment is correct. In cygwin (May 2016), « doesn’t work while $() works. Couldn’t fix until I saw this page.

The original Bourne shell supported backticks , but not $(. ) notation. So you need to use backticks if you require compatibility with older Unix systems.

Some Bash tricks I use to set variables from commands

Sorry, there is a loong answer. But as bash is a shell, where the main goal is to run other unix commands and react on result code and/or output ( commands are often piped filter, etc. ), storing command output in variables is something basic and fundamental.

  • compatibility (posix)
  • kind of output (filter(s))
  • number of variable to set (split or interpret)
  • execution time (monitoring)
  • error trapping
  • repeatability of request (see long running background process, further)
  • interactivity (considering user input while reading from another input file descriptor)
  • do I miss something?

First simple, old (obsolete), and compatible way

myPi=`echo '4*a(1)' | bc -l` echo $myPi 3.14159265358979323844 

Compatible, second way

As nesting could become heavy, parenthesis was implemented for this

Using backticks in script is to be avoided today.

Nested sample:

SysStarted=$(date -d "$(ps ho lstart 1)" +%s) echo $SysStarted 1480656334 

bash features

Reading more than one variable (with Bashisms)

df -k / Filesystem 1K-blocks Used Available Use% Mounted on /dev/dm-0 999320 529020 401488 57% / 

If I just want a used value:

you could see an array variable:

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]="/")' 

But I often use this:

( The first read _ will just drop header line. ) Here, in only one command, you will populate 6 different variables (shown by alphabetical order):

declare -p avail filesystem mountpoint prct size using declare -- avail="401488" declare -- filesystem="/dev/dm-0" declare -- mountpoint="/" declare -- prct="57%" declare -- size="999320" declare -- using="529020" 
declare -p varnames $ declare -a varnames=([0]="Filesystem" [1]="blocks" [2]="Used" [3]="Available" [4]="Use" [5]="Mounted" [6]="on") declare -- filesystem="/dev/dm-0" declare -- blocks="999320" declare -- used="529020" declare -- available="401488" declare -- use="57%" declare -- mounted="/" declare -- on="" 

(Note Used and Blocks is switched there: read . dsk[6] dsk[2] dsk[9] . )

. will work with associative arrays too: read _ disk[total] disk[used] .

Other related sample: Parsing xrandr output: and end of Firefox tab by bash in a size of x% of display size? or at AskUbuntu.com Parsing xrandr output

Dedicated fd using unnamed fifo:

There is an elegent way! In this sample, I will read /etc/passwd file:

users=() while IFS=: read -u $list user pass uid gid name home bin ;do ((uid>=500)) && printf -v users[uid] "%11d %7d %-20s %s\n" $uid $gid $user $home done  

Using this way ( . read -u $list; . STDIN free for other purposes, like user interaction.

echo -n "$" 1000 1000 user /home/user . 65534 65534 nobody /nonexistent 
echo $ 1000 . 65534 echo -n "$" 1000 1000 user /home/user 

This could be used with static files or even /dev/tcp/xx.xx.xx.xx/yyy with x for ip address or hostname and y for port number or with the output of a command:

< read -u $list -a head # read header in array `head` varnames=($) # drop illegal chars for variable names while read -u $list $ ;do ((pct=available*100/(available+used),pct<10)) && printf "WARN: FS: %-20s on %-14s %3d <10 (Total: %11u, Use: %7s)\n" \ "$" "$mounted" $pct $blocks "$use" done > < <(LANG=C df -k) 

And of course with inline documents:

while IFS=\; read -u $list -a myvar ;do echo $ done  

Practical sample parsing CSV files:

As this answer is loong enough, for this paragraph, I just will let you refer to this answer to How to parse a CSV file in Bash? , I read a file by using an unnamed fifo, using syntax like:

. But using bash loadable CSV module.

Sample function for populating some variables:

#!/bin/bash declare free=0 total=0 used=0 mpnt='??' getDiskStat() < < read _ read _ total used free _ mpnt > < <( df -k $<1:-/>) > getDiskStat $1 echo "$mpnt: Tot:$total, used: $used, free: $free." 

Nota: declare line is not required, just for readability.

About sudo cmd | grep . | cut .

shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7) echo $shell /bin/bash 

(Please avoid useless cat ! So this is just one fork less:

All pipes ( | ) implies forks. Where another process have to be run, accessing disk, libraries calls and so on.

So using sed for sample, will limit subprocess to only one fork:

And with Bashisms:

But for many actions, mostly on small files, Bash could do the job itself:

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

Going further about variable splitting.

Alternative: reducing forks by using backgrounded long-running tasks

In order to prevent multiple forks like

myStarted=$(date -d "$(ps ho lstart 1)" +%s) mySessStart=$(date -d "$(ps ho lstart $$)" +%s) 

This work fine, but running many forks is heavy and slow.

And commands like date and bc could make many operations, line by line!!

So we could use a long running background process to make many jobs, without having to initiate a new fork for each request.

You could have a look how reducing forks make Mandelbrot bash, improve from more than eight hours to less than 5 seconds.

Under bash, there is a built-in function: coproc :

coproc bc -l echo 4*3 >&$ read -u $COPROC answer echo $answer 12 echo >&$ 'pi=4*a(1)' ray=42.0 printf >&$ '2*pi*%s\n' $ray read -u $COPROC answer echo $answer 263.89378290154263202896 printf >&$ 'pi*%s^2\n' $ray read -u $COPROC answer echo $answer 5541.76944093239527260816 

As bc is ready, running in background and I/O are ready too, there is no delay, nothing to load, open, close, before or after operation. Only the operation himself! This become a lot quicker than having to fork to bc for each operation!

Border effect: While bc stay running, they will hold all registers, so some variables or functions could be defined at initialisation step, as first write to $ , just after starting the task (via coproc ).

Into a function newConnector

You may found my newConnector function on GitHub.Com or on my own site (Note on GitHub: there are two files on my site. Function and demo are bundled into one unique file which could be sourced for use or just run for demo.)

source 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" 

The function myBc lets you use the background task with simple syntax.

newConnector /bin/date '-f - +%s' @0 0 myDate '2000-01-01' 946681200 myDate "$(ps ho lstart 1)" boottime myDate now now read utm idl 

From there, if you want to end one of background processes, you just have to close its 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 

which is not needed, because all fd close when the main process finishes.

Источник

Linux присвоить значение команды переменной

оператор присваивания ( пробельные символы до и после оператора -- недопустимы )

Обратите внимание: символ = может использоваться как в качестве оператора присваивания, так и в качестве оператора сравнения, конкретная интерпретация зависит от контекста применения.

Пример 4-2. Простое присваивание

#!/bin/bash # Явные переменные echo # Когда перед именем переменной не употребляется символ '$'? # В операциях присваивания. # Присваивание a=879 echo "Значение переменной \"a\" -- $a." # Присваивание с помощью ключевого слова 'let' let a=16+5 echo "Значение переменной \"a\" теперь стало равным: $a." echo # В заголовке цикла 'for' (своего рода неявное присваивание) echo -n "Значения переменной \"a\" в цикле: " for a in 7 8 9 11 do echo -n "$a " done echo echo # При использовании инструкции 'read' (тоже одна из разновидностей присваивания) echo -n "Введите значение переменной \"a\" " read a echo "Значение переменной \"a\" теперь стало равным: $a." echo exit 0

Пример 4-3. Присваивание значений переменным простое и замаскированное

#!/bin/bash a=23 # Простейший случай echo $a b=$a echo $b # Теперь немного более сложный вариант (подстановка команд). a=`echo Hello!` # В переменную 'a' попадает результат работы команды 'echo' echo $a # Обратите внимание на восклицательный знак (!) в подстанавливаемой команде #+ этот вариант не будет работать при наборе в командной строке, #+ поскольку здесь используется механизм "истории команд" BASH # Однако, в сценариях, механизм истории команд запрещен. a=`ls -l` # В переменную 'a' записывается результат работы команды 'ls -l' echo $a # Кавычки отсутствуют, удаляются лишние пробелы и пустые строки. echo echo "$a" # Переменная в кавычках, все пробелы и пустые строки сохраняются. # (См. главу "Кавычки.") exit 0
# Взято из /etc/rc.d/rc.local R=$(cat /etc/redhat-release) arch=$(uname -m)

Источник

Оцените статью
Adblock
detector