0
votes

Est-il possible de simplifier cette expression d'évaluation BASH?

Compte tenu de l'extrait de script du shell Bash suivant:

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

Ainsi, la ligne eval eval ... dans le code précédent peut-elle être simplifiée, tout en produisant sortie souhaitée, qui pour l'exemple ci-dessus est:

# 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

Je pense à une solution qui remplacerait certaines des commandes echo par redirection d'entrée / sortie (peut-être) ou peut-être une sorte de réorganisation / réduction qui entraînerait le besoin de moins de commandes eval que celles utilisées dans l'exemple.


7 commentaires

J'irais pour le "effondrement de toutes sortes" comme l'indique @oguz ismail.


@oguz, j'ai expliqué que nous pourrions être intéressés par certains arguments et pas tous, c'était un exemple de plage équivalent à "$ @" . Voir la dernière phrase du commentaire Exigence / Contrainte intégré dans le code


Pourriez-vous déplacer la prose hors du bloc de code? Il est beaucoup plus facile à lire lorsqu'il est correctement formaté.


Ensuite, vous utiliseriez quelque chose comme "$ {@: 1: 3}" , pas eval.


Je collerais les composants du chemin dans un tableau (pourquoi le définir sur des paramètres de position, nécessitant cette expansion sans guillemets?) Comme IFS =: read -ra arr <<< "$ PATH" et ensuite faire avec le arr tableau ce que je veux.


@oguz, et lorsque vous paramétrez votre 1 et votre 3 pour qu'ils soient dynamiques, vous revenez à ma question initiale


Ensuite, vous utilisez une boucle for ((...)) de style C.


3 Réponses :


1
votes
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
Now you've got every section of the path, in its' own named variable.

2 commentaires

Pas exactement ce que j'ai demandé, mais assez intéressant pour un vote positif.


L'approvisionnement narcissique est toujours apprécié.



1
votes

En vous rapprochant de l'original, vous pouvez faire

set $(sed 's/[^=]*=//;s/:/ /g' <<< ${PATH})
echo "$@"

Si vous ne voulez pas changer IFS et PATH , vous peut faire

IFS=:
set $PATH
echo "$@"


1 commentaires

Vous avez un point-virgule de trop, mon ami. Il doit être: set $ (sed 's / [^ =] * = //; s /: / / g' <<< $ {PATH}); echo "$ @" . Certainement une prise intéressante, si ce n'est dans les lignes directrices de la question. Dans tous les cas, faites un vote positif ( et remplacez ce deuxième point-virgule dans la commande sed par un signe deux-points - ce n'est pas Windows ).



0
votes

mais produit toujours le résultat souhaité,
/ usr / local / bin / usr / bin / bin

Juste :

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

L'intention est de prendre la variable d'environnement PATH, de la diviser en ses parties, en les faisant semblent être des arguments de ligne de commande (c'est-à-dire $ 1 , $ 2 , ...), puis pour cet exemple, juste faire écho aux parties sous une forme délimitée par un espace, mais nous pouvons imaginer que nous voudrions peut-être faire d'autres choses avec eux - ceci est juste un exemple d'utilisation

Je ne fais pas confiance aux extensions de shell sans guillemets.

echo "${PATH//:/ }"

0 commentaires