J'ai une variable dans mon script bash dont la valeur est quelque chose comme ceci:
~/a/b/c
Notez qu'il s'agit d'un tilde non développé. Quand je fais ls -lt sur cette variable (appelez-la $ VAR), je n'obtiens pas un tel répertoire. Je veux laisser bash interpréter / développer cette variable sans l'exécuter. En d'autres termes, je veux que bash exécute eval mais pas la commande évaluée. Est-ce possible en bash?
Comment ai-je réussi à transmettre cela dans mon script sans extension? J'ai passé l'argument en l'entourant de guillemets doubles.
Essayez cette commande pour voir ce que je veux dire:
ls -lt "~"
C'est exactement la situation dans laquelle je me trouve. Je veux que le tilde soit élargi. En d'autres termes, par quoi dois-je remplacer la magie pour rendre ces deux commandes identiques:
ls -lt ~/abc/def/ghi
et
ls -lt $(magic "~/abc/def/ghi")
Notez que ~ / abc / def / ghi peut exister ou non.
la source
eval
.foo=~/"$filepath"
oufoo="$HOME/$filepath"
dir="$(readlink -f "$dir")"
Réponses:
En raison de la nature de StackOverflow, je ne peux pas simplement rendre cette réponse non acceptée, mais au cours des 5 années écoulées depuis que j'ai publié cela, il y a eu de bien meilleures réponses que ma réponse, certes rudimentaire et plutôt mauvaise (j'étais jeune, ne tuez pas moi).
Les autres solutions de ce fil sont des solutions plus sûres et meilleures. De préférence, j'irais avec l'un de ces deux:
Réponse originale à des fins historiques (mais veuillez ne pas l'utiliser)
Si je ne me trompe pas,
"~"
ne sera pas développé par un script bash de cette manière car il est traité comme une chaîne littérale"~"
. Vous pouvez forcer l'expansion viaeval
comme ça.Sinon, utilisez simplement
${HOME}
si vous voulez le répertoire personnel de l'utilisateur.la source
${HOME}
plus attrayant. Y a-t-il une raison de ne pas en faire votre principale recommandation? En tout cas, merci!eval
est une suggestion horrible, c'est vraiment mauvais qu'elle reçoive autant de votes positifs. Vous rencontrerez toutes sortes de problèmes lorsque la valeur de la variable contient des méta caractères du shell.Si la variable
var
est entrée par l'utilisateur, neeval
doit pas être utilisée pour développer le tilde en utilisantLa raison est: l'utilisateur pourrait par accident (ou par but) taper par exemple
var="$(rm -rf $HOME/)"
avec des conséquences désastreuses possibles.Une meilleure méthode (et plus sûre) consiste à utiliser l'expansion des paramètres Bash:
la source
#
in"${var/#\~/$HOME}"
?$var
.\~
s'échapper~
? (2) Votre réponse suppose que~
c'est le premier caractère de$var
. Comment pouvons-nous ignorer les principaux espaces blancs$var
?:
dans une chaîne non entre guillemets. Plus d'informations dans la documentation . Pour supprimer les espaces blancs de début, consultez Comment couper les espaces d'une variable Bash?Je me plagarise à partir d' une réponse précédente , pour le faire de manière robuste sans les risques de sécurité associés à
eval
:...utilisé comme...
Alternativement, une approche plus simple qui utilise
eval
avec soin:la source
printf %q
pour échapper à tout , mais le tilde, et puis utilisereval
sans risque.Un moyen sûr d'utiliser eval est
"$(printf "~/%q" "$dangerous_path")"
. Notez que c'est spécifique à bash.Voir cette question pour plus de détails
Notez également que sous zsh, ce serait aussi simple que
echo ${~dangerous_path}
la source
echo ${~root}
ne me donne pas de sortie sur zsh (mac os x)export test="~root/a b"; echo ${~test}
Que dis-tu de ça:
Ou:
la source
realpath
commande en C. Par exemple, vous pouvez générer un exécutable enrealpath.exe
utilisant bash et gcc à partir de cette ligne de commande:gcc -o realpath.exe -x c - <<< $'#include <stdlib.h> \n int main(int c,char**v){char p[9999]; realpath(v[1],p); puts(p);}'
. Cheersrealpath ~
->/home/myhome
<workingdir>/~
.Expansion (sans jeu de mots) sur les réponses de birryree et halloleo: L'approche générale est d'utiliser
eval
, mais elle s'accompagne de quelques mises en garde importantes, à savoir les espaces et la redirection de sortie (>
) dans la variable. Ce qui suit semble fonctionner pour moi:Essayez-le avec chacun des arguments suivants:
Explication
${mypath//>}
supprime les>
caractères qui pourraient écraser un fichier pendant leeval
.eval echo ...
ce que fait l'expansion réelle du tilde-e
argument sont pour la prise en charge des noms de fichiers avec des espaces.Il existe peut-être une solution plus élégante, mais c'est ce que j'ai pu proposer.
la source
$(rm -rf .)
.>
caractères?Je crois que c'est ce que tu cherches
Exemple d'utilisation:
la source
printf %q
n'échappe pas aux principaux tildes - il est presque tentant de signaler cela comme un bogue, car c'est une situation dans laquelle il échoue à son objectif déclaré. Cependant, en attendant, un bon appel!Voici ma solution:
la source
echo
signifie que celaexpandTilde -n
ne se comportera pas comme prévu, et le comportement avec des noms de fichiers contenant des barres obliques inverses n'est pas défini par POSIX. Voir pubs.opengroup.org/onlinepubs/009604599/utilities/echo.htmlUtilisez simplement
eval
correctement: avec validation.la source
printf %q
pour échapper aux choses en toute sécurité plus que je ne fais confiance au code de validation écrit à la main pour ne pas avoir de bogues .printf
est une$PATH
commande 'd.bash
? Si telprintf
est le cas, est une fonction intégrée et%q
est garantie d'être présente.bash
assez utilisé avant de savoir ne pas lui faire confiance. essayer:x=$(printf \\1); [ -n "$x" ] || echo but its not null!
Voici la fonction POSIX équivalente à la réponse Bash de Håkon Hægland
10/12/2017 edit: ajoutez
'%s'
par @CharlesDuffy dans les commentaires.la source
printf '%s\n' "$tilde_less"
, peut-être? Sinon, il se comportera mal si le nom de fichier en cours de développement contient des barres obliques inverses%s
, ou une autre syntaxe significative pourprintf
. En dehors de cela, cependant, c'est une excellente réponse - correcte (quand les extensions bash / ksh n'ont pas besoin d'être couvertes), évidemment sûre (pas de bavardage aveceval
) et laconique.pourquoi ne pas se plonger directement dans l'obtention du répertoire personnel de l'utilisateur avec getent?
la source
Juste pour étendre la réponse de birryree pour les chemins avec des espaces: vous ne pouvez pas utiliser la
eval
commande telle quelle car elle sépare l'évaluation par des espaces. Une solution consiste à remplacer temporairement les espaces pour la commande eval:Cet exemple repose bien sûr sur l'hypothèse de
mypath
ne jamais contenir la séquence char"_spc_"
.la source
$(rm -rf .)
Vous trouverez peut-être cela plus facile à faire en python.
(1) Depuis la ligne de commande unix:
Résulte en:
(2) Dans un script bash en une seule fois - enregistrez-le sous
test.sh
:L'exécution des
bash ./test.sh
résultats en:(3) En tant qu'utilitaire - enregistrez-le
expanduser
quelque part sur votre chemin, avec les autorisations d'exécution:Cela pourrait ensuite être utilisé sur la ligne de commande:
Ou dans un script:
la source
echo $thepath
est buggy; doit êtreecho "$thepath"
de corriger les cas moins rares (les noms avec des tabulations ou des séries d'espaces étant convertis en espaces simples; les noms avec des globs les ayant développés), ouprintf '%s\n' "$thepath"
de corriger les plus rares aussi (c'est-à-dire un fichier nommé-n
, ou un fichier avec les littéraux anti-slash sur un système compatible XSI). De même,thepath=$(expanduser "$1")
echo
de se comporter d'une manière complètement définie par l'implémentation si un argument contient des anti-slash; les extensions XSI facultatives de POSIX imposent des comportements d'expansion par défaut (pas-e
ou-E
nécessaires) pour ces noms.Le plus simple : remplacez «magic» par «eval echo».
Problème: vous allez rencontrer des problèmes avec d'autres variables car eval est mauvais. Par exemple:
Notez que le problème de l'injection ne se produit pas lors de la première expansion. Donc, si vous deviez simplement remplacer
magic
pareval echo
, vous devriez être d'accord. Mais si vous le faitesecho $(eval echo ~)
, ce serait susceptible d'être injecté.De même, si vous le faites à la
eval echo ~
placeeval echo "~"
, cela compterait comme deux fois expansé et l'injection serait donc possible immédiatement.la source
s='echo; EVIL_COMMAND'
. (Il échouera car ilEVIL_COMMAND
n'existe pas sur votre ordinateur. Mais si cette commande avait étérm -r ~
par exemple, elle aurait supprimé votre répertoire personnel.)J'ai fait cela avec une substitution de paramètre variable après la lecture du chemin en utilisant read -e (entre autres). Ainsi, l'utilisateur peut compléter le chemin par tabulation, et si l'utilisateur entre un chemin ~, il est trié.
L'avantage supplémentaire est que s'il n'y a pas de tilde, rien n'arrive à la variable, et s'il y a un tilde mais pas en première position, il est également ignoré.
(J'inclus le -i pour la lecture puisque j'utilise ceci dans une boucle afin que l'utilisateur puisse réparer le chemin s'il y a un problème.)
la source