Skip to content

Instantly share code, notes, and snippets.

@YumaInaura
Last active August 12, 2018 03:22
Show Gist options
  • Save YumaInaura/838cac70898062585f90206861ccb7e9 to your computer and use it in GitHub Desktop.
Save YumaInaura/838cac70898062585f90206861ccb7e9 to your computer and use it in GitHub Desktop.
Shell—Understanding eval behaviour ( with random command example )

It is just string assignment

So subcommand is not executed in this line's timing

echo_random_command_as_string='echo $((RANDOM))' 

When not use eval, just echo string

$echo_random_command_as_string # $((RANDOM))

Eval : execute command from string

These lines execute echo $((RANDOM)) everytime

eval $echo_random_command_as_string  # e.g 76811 : randomized every time
eval $echo_random_command_as_string  # e.g 345   : randomized every time
eval $echo_random_command_as_string  # e.g 6532  : randomized every time

This is a wrong case ( not exepected result )

Subcommand is executed immediately when assignment

So variable got fixed string like 'echo 3457'

echo_random_fixed="echo $((RANDOM))"

$echo_random_fixed # e.g 3457 : not randomized every time
$echo_random_fixed # e.g 3457 : not randomized every time
$echo_random_fixed # e.g 3457 : not randomized every time

Shell—Understanding eval behaviour ( with random command example )

#!/bin/bash -eu

echo_alice_and_bob='echo alice; echo bob'

$echo_alice_and_bob       # alice; echo bob
eval $echo_alice_and_bob  # alice # bob


echo_carol_and_david='echo carol && echo david'

$echo_carol_and_david       # bob && echo carol
eval $echo_carol_and_david  # bob # carol

$echo_alice_and_bob $echo_carol_and_david       # alice; echo bob echo carol && echo david
eval $echo_alice_and_bob $echo_carol_and_david  # alice # bob echo carol

Variable (parameter) substitution happens as shell syntax

It is not special for eval command.

echo=echo
ok=ok

eval "$echo" "$ok" # ok
echo=echo
ok=ok
eval=eval

"$eval" "$echo" "$ok" # ok
https://gist.github.com/YumaInaura/838cac70898062585f90206861ccb7e9
#!/bin/bash -eu
echo_alice_and_bob='echo alice; echo bob'
$echo_alice_and_bob # alice; echo bob
eval $echo_alice_and_bob # alice # bob
echo_carol_and_david='echo carol && echo david'
$echo_carol_and_david # bob && echo carol
eval $echo_carol_and_david # bob # carol
$echo_alice_and_bob $echo_carol_and_david # alice; echo bob echo carol && echo david
eval $echo_alice_and_bob $echo_carol_and_david # alice # bob echo carol
+ echo_alice_and_bob='echo alice; echo bob'
+ echo 'alice;' echo bob
alice; echo bob
+ eval echo 'alice;' echo bob
++ echo alice
alice
++ echo bob
bob
+ echo_carol_and_david='echo carol && echo david'
+ echo carol '&&' echo david
carol && echo david
+ eval echo carol '&&' echo david
++ echo carol
carol
++ echo david
david
+ echo 'alice;' echo bob echo carol '&&' echo david
alice; echo bob echo carol && echo david
+ eval echo 'alice;' echo bob echo carol '&&' echo david
++ echo alice
alice
++ echo bob echo carol
bob echo carol
++ echo david
david
#!/bin/bash
# comment
# commnnt
code
code
# comment
code
code # codecomment
code
#!/bin/bash
docker build . -t shell_eval
docker run shell_eval ./run.sh
FROM ubuntu
WORKDIR /script
COPY ./ /script
#!/bin/bash -eux
# Assignment as just string
command='$((RANDOM))'
# It works
# It is equivalent to execute command `echo $((RANDOM))` every times
eval echo "$command" # e.g. 34641
eval echo $command # e.g. 755
eval "echo $command" # e.g. 1235
# Assignment as just string
command='$((RANDOM))'
# It works
# It is equivalent to execute command `echo $((RANDOM))` every times
eval echo "$command" # e.g. 27571
eval echo $command # e.g. 2435
eval "echo $command" # e.g. 2435
+ command='$((RANDOM))'
+ eval echo '$((RANDOM))'
++ echo 30720
30720
+ eval echo '$((RANDOM))'
++ echo 10733
10733
+ eval 'echo $((RANDOM))'
++ echo 7850
7850
+ command='$((RANDOM))'
+ eval echo '$((RANDOM))'
++ echo 22658
22658
+ eval echo '$((RANDOM))'
++ echo 24486
24486
+ eval 'echo $((RANDOM))'
++ echo 32756
32756
#!/usr/bin/env ruby
STDOUT.sync = true
input_file_path = ARGV[0] || (raise 'Please specify file path in command first argument')
output_file_path = ARGV[1] || input_file_path
debug_mode = !!ARGV.detect { |argv| argv == '--debug' }
puts "Start converting"
puts "Input file : #{input_file_path}"
puts "Onput file : #{output_file_path}"
sleep 1
in_codeblock = false
output = ''
# FIXME: Can not use regex named capture with constant
# START_OF_CODE_BLOCK_REGEXP = /\A```([a-z]+)?:(?<import_file_path>[a-z0-9]+\.[a-z]+)/
File.open(input_file_path).each do |line|
chomped_line = line.chomp
if /\A```([a-z]+)?:(?<import_file_path>[^\s]+\.[a-zA-Z]+)/ =~ chomped_line
in_codeblock = true
puts :START_CODEBLOCK if debug_mode
puts line if debug_mode
output += line
output += File.read(import_file_path).gsub(/[\n\r\s]+\z/, '') + "\n"
elsif in_codeblock && '```' == chomped_line
puts :END_CODEBLOCK if debug_mode
puts line if debug_mode
in_codeblock = false
output += line
elsif in_codeblock
puts :DO_NOTHING if debug_mode
else
puts :OTHER_LINE if debug_mode
puts line if debug_mode
output += line
end
end
puts output
File.write(output_file_path, output)
#!/usr/bin/env ruby
STDOUT.sync = true
input_file_path = ARGV[0] || (raise 'Please specify file path in command first argument')
debug_mode = !!ARGV.detect { |argv| argv == '--debug' }
puts "Start converting"
puts "Input file : #{input_file_path}"
sleep 1
in_codeblock = false
file_output = ''
output_file_path_to = nil
File.open(input_file_path).each do |line|
chomped_line = line.chomp
if /\A```([a-z]+)?:(?<output_file_path>[^\s]+\.[a-zA-Z]+)/ =~ chomped_line
output_file_path_to = output_file_path
in_codeblock = true
file_output = ''
puts :START_CODEBLOCK if debug_mode
puts line if debug_mode
elsif in_codeblock && '```' == chomped_line
puts :END_CODEBLOCK if debug_mode
puts line if debug_mode
puts output_file_path_to
File.write(output_file_path_to, file_output)
in_codeblock = false
elsif in_codeblock
puts :FILE_OUTPUT if debug_mode
puts file_output if debug_mode
file_output += line
else
puts :OTHER_LINE if debug_mode
puts line if debug_mode
end
end
#!/bin/bash -eu
chmod +x *.sh
rm -f *.log
for file in $(find . -name '*.sh' | grep -v 'run.sh' | grep -v 'docker.sh'); do
echo --------------------------
echo run "$file"
echo --------------------------
"$file" 2>&1 | tee "$file".log
done
#!/bin/bash -eu
# It is just string assignment
# So subcommand is not executed in this line's timing
```
echo_random_command_as_string='echo $((RANDOM))'
```
# When not use eval, just echo string
```
$echo_random_command_as_string # $((RANDOM))
```
# Eval : execute command from string
# These lines execute `echo $((RANDOM))` everytime
eval $echo_random_command_as_string # e.g 76811 : randomized every time
eval $echo_random_command_as_string # e.g 345 : randomized every time
```
eval $echo_random_command_as_string # e.g 6532 : randomized every time
```
# This is a wrong case ( not exepected result )
# Subcommand is executed immediately when assignment
# So variable got fixed string like 'echo 3457'
```
echo_random_fixed="echo $((RANDOM))"
```
$echo_random_fixed # e.g 3457 : not randomized every time
$echo_random_fixed # e.g 3457 : not randomized every time
```
$echo_random_fixed # e.g 3457 : not randomized every time
```
#!/bin/bash -eu
# It is just string assignment
# So subcommand is not executed in this line's timing
echo_random_command_as_string='echo $((RANDOM))'
# When not use eval, just echo string
$echo_random_command_as_string # $((RANDOM))
# Eval : execute command from string
# These lines execute `echo $((RANDOM))` everytime
eval $echo_random_command_as_string # e.g 76811 : randomized every time
eval $echo_random_command_as_string # e.g 345 : randomized every time
eval $echo_random_command_as_string # e.g 6532 : randomized every time
# This is a wrong case ( not exepected result )
# Subcommand is executed immediately when assignment
# So variable got fixed string like 'echo 3457'
echo_random_fixed="echo $((RANDOM))"
$echo_random_fixed # e.g 3457 : not randomized every time
$echo_random_fixed # e.g 3457 : not randomized every time
$echo_random_fixed # e.g 3457 : not randomized every time
+ echo_random='echo $((RANDOM))'
+ echo '$((RANDOM))'
$((RANDOM))
+ echo_random='echo 32537'
+ echo 32537
32537
+ echo 32537
32537
+ echo 32537
32537
+ echo_random='echo $((RANDOM))'
+ eval echo '$((RANDOM))'
++ echo 13431
13431
+ eval echo '$((RANDOM))'
++ echo 8353
8353
+ eval echo '$((RANDOM))'
++ echo 4252
4252
#!/bin/bash -eux
# Assignment as string
command='$((RANDOM))'
# RANDOM command not executed
# Because it only echo string
echo "$command" # $((RANDOM))
# Assignment with executed command result
command="$((RANDOM))"
# RANDOM command not executed
# Because "$command" variable has just string result ( previous set )
echo "$command" # 31424
echo "$command" # 31424
echo "$command" # 31424
# Assignment with executed command result
command="$((RANDOM))"
eval "$command" # bash: 22019: command not found
eval "$command" # bash: 22019: command not found
eval "$command" # bash: 22019: command not found
# Assignment as string
command='$((RANDOM))'
# Error occurs
# below lines evaluate commands as $((RANDOM)) 3 times
eval "$command" # bash: 22019: command not found
eval "$command" # bash: 375: command not found
eval "$command" # bash: 7007: command not found
+ command='$((RANDOM))'
+ echo '$((RANDOM))'
$((RANDOM))
+ command=678
+ echo 678
678
+ echo 678
678
+ echo 678
678
+ command=14781
+ eval 14781
++ 14781
./unexpected.sh: line 23: 14781: command not found
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment