bash: un problème lors de l'utilisation de la lecture <<< “$ VARIABLE” sur une partition racine en lecture seule. Des solutions de contournement connues?


11

Par pure coïncidence, j'ai dû utiliser mon script ATA-ID-to-device-name (trouvé ici: /server/244944/linux-ata-errors-translating-to-a-device-name/ 426561 # 426561 ) sur une partition en lecture seule / . Au cas où vous seriez curieux, c'était une console de récupération Ubuntu qui vous permettra d'accéder à votre /partition, mais la montera en lecture seule par défaut. Je m'en réjouis, car sinon je n'aurais probablement jamais découvert que mon script se comportait étrangement sur un système R / O en raison d'une ligne spécifique, celle-ci:

IFS=: read HostMain HostMid HostSub <<< "$HostFull"

Cela ne fonctionne pas s'il n'y a aucune autorisation d'écriture. Je n'aurais pas pensé que cela échouerait cependant. Mais apparemment , l' <<<opérateur ne nécessite d'écrire du fichier temporaire à quelque part.

Mais existe-t-il un moyen de contourner la création d'un fichier temporaire ou existe-t-il un moyen de spécifier où le fichier est écrit? Dans la console de récupération d'Ubuntu, il y a --- assez bizarrement --- la permission d'écrire sur le /runrépertoire, ce qui ferait l'affaire, si je pouvais en quelque sorte "dire" readd'écrire le fichier temporaire ailleurs que d'habitude.


2
@gniourf_gniourf Non, "ouvrir un descripteur de fichier" ne serait pas un problème (pourquoi le ferait-il?), et /dev/fdn'a rien à voir avec cela. <<<est le coupable, car il crée un fichier temporaire (qui doit être écrit quelque part).
Gilles 'SO- arrête d'être méchant'

Réponses:


8

Un tableau pourrait faire l'analyse de la chaîne sans avoir besoin d'un fichier temporel. N'oubliez pas de désactiver le globbing.

set -f
IFS=: Hosts=($HostFull)
HostMain=${Hosts[0]}
HostMid=${Hosts[1]}
HostSub=${Hosts[2]}
set +f

2
ou même sans IFS, si vous êtes sûr qu'il n'y a pas d' espaces dans $HostFullcomme ceci: Hosts=( ${HostFull//:/ } ). Ou même s'il y a des espaces: HostMain=${HostFull%%:*}; HostMid=${HostFull#*:}; HostSub=${HostMid#*:}; HostMid=${HostMid%:*}(ou quelque chose de similaire, je m'embrouille :D).
gniourf_gniourf

Vous avez raison, car vous montrez que l'expansion des paramètres est délicate pour les entreprises ...
xae

4

Je suis d'accord avec @gniourf_gniourf, vous avez probablement besoin d'un accès en écriture mais pas aux descripteurs de fichiers, probablement un fichier.

Vous pouvez tester cela en retraçant l'exécution de votre commande dans la partition en lecture seule.

{ strace -p "$$" & sleep 1; read var1 <<< "hi"; sleep 1; kill "$1"; }

Ce qui précède s'exécutera stracesur le shell Bash (processus $$). Il dort ensuite pendant 1 seconde, puis exécute le à readpartir de la chaîne ICI. J'ai mis la chaîne "hi"dans cette position. J'ai ensuite sleepune seconde de plus puis killle strace.

Exemple

Lors de l'analyse de cette sortie, vous remarquerez qu'un fichier est ouvert en tant que O_WRONLY, ce qui est destiné à l'écriture dans un fichier.

open("/tmp/sh-thd-4137571604", O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600) = 3

Ci-dessus, nous pouvons voir dans quel fichier est écrit votre séquence de commandes.


1
Ne pas «créer les descripteurs de fichiers» (cela n'a aucun sens). Pour créer le fichier . Ce n'est pas readça qui ouvre un fichier pour l'écriture (ce serait idiot), ça l'est <<<.
Gilles 'SO- arrête d'être méchant'

@ Gilles - merci, je n'ai pas bien compris ce que ça me disait. Nettoyé le A.
slm

Merci beaucoup! Une très belle technique, qui pourrait même m'aider plusieurs fois à l'avenir avec des problèmes similaires. Cependant, une chose est me inquiète, et qui est le fait que /tmpest un hardcoded chemin. Et vous l'avez probablement deviné, /tmp EST déjà là, mais aussi en lecture seule! Et puisque travailler sur cette console de récupération me fera me connecter à mon système de fichiers en direct , je ne voudrais pas me déranger là-bas par lien symbolique ou autre (même pas dans cette console).
erreur de syntaxe

3

Je trouve les paramètres positionnels très utiles pour ce genre de tâche. Il est également généralement portable pour tous les shells, et ne coûte ni fourches ni fichiers temporaires.

$ HostFull=main:mid:sub    
$ oldIFS=$IFS; IFS=:; set -- $HostFull; IFS=$oldIFS
$ echo $1
main
$ echo $2
mid
$ echo $3
sub

Une bonne approche! Je vous remercie. De plus, j'aime qu'il ne nécessite aucun outil externe (que nous ne devons généralement pas trouver dans ces environnements restreints de toute façon). La seule chose qui peut causer des ennuis est $1, $2, des $3choses: rappelez - vous que dans un script, ce sera généralement un support argument passé au script lui - même . - Et tant que nous y sommes: si IFS est censé être un espace, * IFS = * ne fonctionnera pas dans cette syntaxe; vous devrez spécifier IFS = '' explicitement.
erreur de syntaxe
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.