bash - expansion du paramètre de tableau en arguments

1

J'essaie de construire une interface utilisateur de sélection de cerises pour Git. La sortie de git logproduit des lignes comme celle-ci:

e9dfe65  "Alice, 78 minutes ago - Thumbnails are now 300x300" no
3b780ba  "Bob, 3 hours ago - new intro page" no
7ba8120  "Charles, 20 hours ago - add cutoff date for widget timing" no

Je veux passer ceci comme arguments à un dialogue pour une liste de contrôle:

dialog --checklist "Choose commits to cherry-pick:" 0 0 0 ...

Malheureusement, je n'arrive pas à comprendre comment passer la sortie de git-log en tant qu'argument pour dialoguer.

Les autres arguments de dialogue sont 3-tuples, tels que <commit> <message> <selected>, d’où le formatage de git-log ci-dessus. Je n'arrive pas à comprendre l'expansion.

Quelques tests:

$ git log ... >temp

$ args="$(cat temp)" ; echo $args[2]
9                                    // WRONG

$ args=`cat temp` ; echo $args[2]              
9                                    // WRONG

$ args=(`cat temp`) ; echo $args[2] 
"Alice,                              // WRONG

Mise à jour: le résultat correct pour $args[2]devrait être Alice, 78 minutes ago - Thumbnails are now 300x300.

un nerd payé
la source
La raison pour laquelle le dernier ne fonctionne pas, c'est que le shell traite l' "entrée en tant que cas spécial pour inclure une chaîne pouvant contenir des espaces. Ce comportement est perdu lorsque les guillemets sont lus à partir de la sortie d'un programme, ce qui est similaire à l'écriture \"sur la ligne de commande.
Daniel Beck
Ce n'est pas clair pour moi, quel serait le bon résultat ici.
Zoredache
@Zoredache Oups, mis à jour.
Un nerd payé

Réponses:

2

Vous pouvez utiliser le code suivant pour remplacer tous les espaces d'une ligne, à l'exception du premier et du dernier, par un caractère d'espacement insécable, que le shell ne considère pas comme un espace.

awk '{ x=$2; for(i=3;i<NF;i++){x=x " " $i }; print $1 " " x " " $NF }' temp

Pour supprimer également les guillemets (malheureusement, tous les guillemets), utilisez:

awk '{ gsub(/"/, ""); x=$2; for(i=3;i<NF;i++){x=x " " $i }; print $1 " " x " " $NF }' temp

Pour vérifier que cela fonctionne:

$ awk '…' temp | cut -d" " -f1
e9dfe65
3b780ba
7ba8120
$ awk '…' temp | cut -d" " -f2
Alice, 78 minutes ago - Thumbnails are now 300x300
Bob, 3 hours ago - new intro page
Charles, 20 hours ago - add cutoff date for widget timing

Le super utilisateur interrompt ma réponse. Ce caractère espace entre guillemets x=x " " $iest supposé être 0xC2A0, un point de code Unicode U+00A0.

Daniel Beck
la source
1

un petit changement à IFS, et quelques espaces blancs, et vous pouvez tirer les arguments, mais ce n'est pas exactement un one-liner.

#!/usr/bin/bash

# log format:
# 
# $one  $two               $three
# nnnnn "mmmm mmm mmm mmm" zzzzzz

# save the current IFS, to restore
OLDIFS=$IFS

# set the new IFS to " marks
IFS='"'
cat /tmp/log | while read one two three; do
        # strip the whitespace from $one and $three
        one="$(echo $one | sed -e 's/ //g')"
        three="$(echo $one | sed -e 's/ //g')"
        # print in brackets to see what falls where
        echo "[$one]: [$two] [$three]"
done

# reset the IFS
IFS=$OLDIFS

À partir de là, votre ligne est divisée, en maintenant le champ intermédiaire cité, et vous pouvez en faire ce que vous souhaitez.

Tim Kennedy
la source