2016-01-13 1 views
0

J'ai un fichier à un moment donné contient une ligne comme ce qui suit:Bash - comment remplacer une ligne commençant par un modèle avec plusieurs lignes définies dans une variable?

VIRTUAL_ENV="/afs/sern.ch/user/l/lronhubbard/virtual_environment" 

Il est la seule ligne dans le fichier qui commence par VIRTUAL_ENV. En utilisant un script, je veux remplacer cette ligne par les lignes suivantes:

directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 
directory_env="$(dirname "${directory_bin}")" 
VIRTUAL_ENV="${directory_env}" 

Comment cela a-t-il pu être fait?

Pour commencer, j'ai les lignes de remplacement stockées dans un document en ligne dans le script:

IFS= read -d '' text << "EOF" 
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 
directory_env="$(dirname "${directory_bin}")" 
VIRTUAL_ENV="${directory_env}" 
EOF 

Ensuite, je peux remplacer la ligne dans le fichier avec autre chose (ici, xxx) en utilisant sed:

sed -i "s/^VIRTUAL_ENV.*/xxx/g" test.txt 

maintenant, comment puis-je utiliser défini ici document à données variables ${text}, avec toutes ses nouvelles lignes et ainsi de suite, au lieu de xxx dans la commande sed?


EDIT: Suite à la suggestion rslemos, je l'ai mis en œuvre le suivant à l'aide d'un fichier temporaire au lieu d'un document en:

#!/bin/bash 

temporary_filename="$(tempfile)" 

cat > "${temporary_filename}" << "EOF" 
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 
directory_env="$(dirname "${directory_bin}")" 
VIRTUAL_ENV="${directory_env}" 
EOF 

sed -i "/^VIRTUAL_ENV.*/ { 
    r ${temporary_filename} 
    d 
}" test.txt 

rm "${temporary_filename}" 

Je voudrais encore savoir comment utiliser un document ici directement de sorte que je n'utilise pas inutilement le disque dur.

+0

Veuillez ne pas poster de réponse dans le cadre de la question. Si vous voulez ajouter votre propre réponse, postez-la en guise de réponse. – tripleee

Répondre

2

j'irais avec sed seul:

/^VIRTUAL_ENV/{ 
r source.txt 
d 
} 

Où source.txt est le fichier où se trouvent les nouvelles lignes pour remplacer une ligne commençant par « VIRTUAL_ENV ».

Si vous avez vraiment besoin des nouvelles lignes (source.txt) pour être un document ici, l'astuce /dev/fd/0 fonctionnera (sous Linux au moins). Mais vous pouvez également combiner mktemp et mkfifo.

EDIT

Pour répondre à la "Je voudrais encore savoir comment utiliser un document en directement":

!/bin/bash 

sed -e '/^VIRTUAL_ENV/{' -e 'r /dev/fd/0' -ed -e'}' test.txt << "EOF" 
directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 
directory_env="$(dirname "${directory_bin}")" 
VIRTUAL_ENV="${directory_env}" 
EOF 

Pas très portable, à cause de la partie /dev/fd/0 (fonctionne sous Linux, cependant).

0

De nombreux dialectes de sed vous permettent d'échapper à la substitution des nouvelles lignes:

sed -i 's/^VIRTUAL_ENV.*/directory_bin="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"\ 
directory_env="$(dirname "${directory_bin}")"\ 
VIRTUAL_ENV="${directory_env}"/' test.txt 

C'est une chaîne unique cité couvrant trois lignes avec une barre oblique ajoutée pour la continuation à chaque limite de ligne interne.

Ceci n'est pas portable pour tous les modèles sed, mais fonctionne bien sur * BSD (y compris OSX) et Linux au moins.Incidemment, vous pouvez également simplement mettre toutes ces commandes sur une seule ligne, avec des points-virgules entre eux.

+0

Le drapeau '/ g' était clairement inutile ici, alors je l'ai retiré. – tripleee

1

Cela pourrait fonctionner pour vous (GNU sed & bash):

cat <<\! | sed $'/PATTERN/{r /dev/stdin\n;d}' file 
HERE DOCUMENT 
STUFF 
HERE 
! 

Utilisez cat pour tuyau la stdin dans la commande sed et le lire comme un fichier en utilisant la commande r.

N.B. \! cite tout le texte dans le document ici utilise ! pour interpoler des variables. $'...' permet aux commandes ayant besoin d'un saut de ligne (à savoir des commandes sed comme r, a, i, c, R, w, W) devant être écrites sur une seule ligne.