Можно ли упростить это выражение BASH eval? - PullRequest
0 голосов
/ 04 августа 2020

Учитывая следующий фрагмент сценария оболочки Bash:

# The intent is to take the PATH env variable, break it up into its parts, making them
# appear to be command line args (i.e., `$1`, `$2`, ...), and then for this example, just
# echo the parts in space delimited form, but we can imagine that we may want to do other
# things with them - this is just sample usage

# Important Requirement/Constraint
# ================================
# Please do not alter the "PATH to $1, $2, $3, ..." portion of the answer or replace the
# Bash ".." range construct with the output of the "seq" command exec'd in a subshell.
# Preferably, the answer should simply consist of the simplification of the last line of
# code - the "eval eval ..." . Also, please don't simplify by collapsing the whole thing
# to just echo "$@" since we may want to work with only some of the parts, and not
# necessarily the first parts, of the path. That is to say that the 1 and $# in the
# {1..$#} range could be replaced with other shell variables or expr., potentially

# Test case
PATH=/usr/local/bin:/usr/bin:/bin

# The code being examined follows

# Set ':' as the input field separator of the path
IFS=: # Or, more appropriately if in a function: local IFS=:

# Parse the PATH environment variable and break it up into its components
set $PATH

# This is the line we want to simplify, if possible, without losing functionality of
# course (see the comment that follows for details)
eval eval echo '\'$(eval 'echo "\${1..$#}"')

# Some notes and explanations regarding the functionality and underlying intent of the
# preceding line:
#   - We start by dynamically creating the following construct: ${1..3}
#     since $# is 3 for our example
#   - Use Bash to expand that construct to: $1 $2 $3
#     these vars contain the parsed parts of the PATH
#   - Finally, display the three parts of the PATH using echo: echo $1 $2 $3
#   - This causes the following text to be sent to STDOUT:
#     /usr/local/bin /usr/bin /bin

Итак, можно ли упростить строку eval eval... в предыдущем коде, но при этом получить желаемый результат, который для приведенного выше примера :

/usr/local/bin /usr/bin /bin

Я думаю о решении, которое заменило бы некоторые из команд echo перенаправлением ввода / вывода (возможно) или, возможно, переупорядочиванием / сворачиванием видов, которое привело бы к требуется меньше eval команд, чем используется в примере.

Ответы [ 3 ]

1 голос
/ 05 августа 2020

Придерживаясь оригинала, вы можете

IFS=:
set $PATH
echo "$@"

Если вы не хотите менять IFS и PATH, вы можете сделать

set $(sed 's/[^=]*=//;s/:/ /g' <<< ${PATH})
echo "$@"
1 голос
/ 04 августа 2020
echo "${PATH}" | tr ':' '\n' > stack

count=1

echo "#/bin/sh-" | tr '-' '\n' >> stack2 

while read line 
do
echo "path${count}=${line}" >> stack2
count=$(($count+1))
done < stack

source stack2

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

0 голосов
/ 05 августа 2020

, но все равно производить желаемый результат, / usr / local / bin / usr / bin / bin

Просто:

echo "${PATH//:/ }"

Цель состоит в том, чтобы взять переменную env PATH, разбить ее на частей, заставляя их выглядеть как аргументы командной строки (например, $1, $2, ...), а затем для этого примера просто отображать части в форме, разделенной пробелами, но мы можем представить, что мы можем захотеть делать с ними другие вещи - это просто пример использования

Я не доверяю расширениям оболочки без кавычек.

IFS=':' read -ra patharr <<<"$PATH"
set -- "${patharr[@]}"
IFS=' '; printf "%s\n" "${patharr[*]}"
...