Contenu | Rechercher | Menus

Annonce

Ubuntu 16.04 LTS
Commandez vos DVD et clés USB Ubuntu-fr !

Pour en savoir un peu plus sur l'équipe du forum.

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

#1 Le 22/03/2017, à 12:31

kholo

[TUTO - BASH] parser un fichier texte : ajout supp insert échange

Bonjour à tous,
je vous soumet un travail sur lequel j'évolue :
Ce script est une base à un parseur de csv en bash,
il montre l'utilisation des tableaux et d'autres trucs glanés à droite et à gauche.
NB : il reste un zenity pour indiquer l'enregistrement

ROLE :
Il charge un fichier texte ligne par ligne dans un tableau
NB2 : les numéros de ligne commencent à 0
permet des actions sur ce fichier :
ajouter, insérer, supprimer, remplacer

Là où j'en suis :
Pour voir son fonctionnement je vous propose 3 fichiers
- un fichier à modifier (on va mettre csv wink ),
- le parseur (reader.sh)
- et un lanceur (pour voir comment reader.sh se lance)

pour tester
créer un dossier

mkdir parseur
cd parseur

créer les trois fichiers (copier / coller le texte d'en dessous)
touch, gedit, nano...

gedit test.csv 

...

rendre les sh exécutable

chmod +x *.sh

tester :

./lanceur.sh

puis

cat test.csv

LES FICHIERS
le fichier texte
test.csv

0|un nom|une réf|une date|valeur|valeur1|valeur2|valeur3|valeur4
1|machine|7,456|'titi'|01/01/2010|45|67|45|67|45
2|gdfgdgf|7dgd456|jygjkg|'zaeaze'|'plein de quote"|et encore|45|67|45
3|kjfkj||||||||
4|gdfgdgf|7dgd456|jygjkg|zaeaze|"encore du texte"|et encore|45|67|45
5|tete|123,12346|titi|20/03/2017|100|200|300|400|500 600
6|poiuytr|4679|nini|10/04/2021|un nom|un autre|le troise|leu cat|et de cinq
7|leu set...

le programme
reader.sh

#!/bin/bash
# ----------------------------------------------
nomlogiciel="${0##*/}"
FONCTION="charge un fichier texte ligne par ligne dans un tableau
permet des actions sur ce fichier :
ajouter, insérer, supprimer, remplacer"
VERSION="0.002"
# NOTES DE VERSIONS
# 
# ----------------------------------------------
echo "
# ----------------------------------------------
lancement $nomlogiciel...
# ----------------------------------------------
" ;
# décommenter pour activer
# MODE_DEBUG=1

function MsgBox () { # texte
	zenity --info --text="$@" ;
	}

function infos () {
echo "Aucun argument à votre demande
${0##*/} 
${FONCTION}

Utilisation :
$0 -f fichier [-a-i-s-r-e] OPTIONS
$0 -f fichier1 [-x] fichier2

a) ajouter Ligne
	-a texte_à_ajouter
i) inserer Ligne
	-i numéro texte_à_insérer
s) supprimer Ligne
	-s numéro_Ligne
r) remplacer Ligne
	-r numéro texte_à_ajouter
e) echanger Ligne1 par Ligne2
	-e numéro numéro
x) executerFichierScript
	-x fichier
"
exit 1
}


# manque arguments informations
[[ ${#@} -lt 1 ]] && infos
[[ ${#@} -lt 1 ]] || echo -e "argument passés : \n$@\n"
# [[ -n "$@" ]] && MsgBox "$@" || infos

# ----------------------------------------------
leFICHIER="" ; 

# ToutesLesLignes
declare -a ToutesLesLignes ; # ToutesLesLignes=[] ;

numLigneCourante=0 ; 
declare -a txtLigneCourante ; # txtLigneCourante=[] ;

declare -a txtTemp ; # txtTemp=[] ;
declare -a tete ; # tete=[] ;

function chargerFichierDanslesLignes () { # fichier : /dossier/mon_fichier.extension
	IFS=$'\n' ;
	local leTexte="$(cat "${@}")" ;
	ToutesLesLignes=( $leTexte ) ;
	}

# ----------------------------------------------
# -a 
function ajouterLigne () { # texte à ajouter au tableau
	ToutesLesLignes[${#ToutesLesLignes[@]}]="$@" ;
	# ou
	# ToutesLesLignes=( ${ToutesLesLignes[@]} "$@" ) ;
	}
# -i 
function insererUneLigne () { # "n° texte à insérer"
	local a=${@%% *}
	local b=${@#* }
	local arr=()

	for ((i=0;i<${a};i++)); do
		arr+=(${ToutesLesLignes[$i]}) 
	done
	arr+=($b) 
	for ((i=${a};i<=$(expr ${#ToutesLesLignes[@]} - 1);i++)); do
		arr+=(${ToutesLesLignes[$i]}) 
	done

	ToutesLesLignes=(${arr[@]})
	}
# -s 
function supprimerUneLigne () { # par numéro Ligne
	unset ToutesLesLignes[$@] ;
	}
# -r 
function remplacerUneLigne () { # num et texte à ajouter au tableau
	local a=${@%% *}
	local b=${@#* }
	ToutesLesLignes[$a]=""
	ToutesLesLignes+=([$a]="$b") ;
	}
# -e 
function echangerLigne1parLigne2 () {
	local L1
	local L2

	local a=${@%% *}
	local b=${@#* }
	L1="${ToutesLesLignes[$a]}"
	L2="${ToutesLesLignes[$b]}"

	ToutesLesLignes[$b]="$L1"
	ToutesLesLignes[$a]="$L2"
	}

# ----------------------------------------------
# -c
function executerFichierScript () {
	# echo "TODO executerFichierScript"
	MsgBox "TODO executerFichierScript"
	}

# ----------------------------------------------
function parser_arguments {
case $@ in
	-f=*|--fichier=*)
			leFICHIER="${@#*=}"
			chargerFichierDanslesLignes "${leFICHIER}"
			;;
	-a=*|--ajouterLigne=*) # texte à ajouter au tableau
			ajouterLigne "${@#*=}"
			;;
	-i=*|--insererUneLigne=*) # "n°" "texte à insérer"
			insererUneLigne "${@#*=}"
			;;
	-s=*|--supprimerUneLigne=*) # par numéro Ligne
			supprimerUneLigne "${@#*=}"
			;;
	-r=*|--remplacerUneLigne=*) # num et texte à ajouter au tableau
			remplacerUneLigne "${@#*=}"
			;;
	-e=*|--echangerLigne1parLigne2=*)
			echangerLigne1parLigne2 "${@#*=}"
			;;
	-x=*|--executerFichierScript=*)
			executerFichierScript "${@#*=}"
			;;

	-h|-?)
			infos
			exit 1
			;;
	-*)
			# MsgBox "${@#*=}"
			echo "${i} : option invalide : ${@#*=}"
			exit 1
			;;
esac
	}

function reader-arg () {
for i in "$@"
do
	# echo -e "i :\n$i"
	parser_arguments "$i"
done
}
reader-arg "$@"

function composerFichierSortie () {
	local ligneEC
	IFS=$'\n' ;
	for ligneEC in ${ToutesLesLignes[@]}
	do
		echo ${ligneEC} ;
	done
	}

function sauverFichier () {
	composerFichierSortie  | tee "$@" ;
	}

[ $MODE_DEBUG ] && {
	# POUR VERIF
	echo "***********************************************************"
	# echo "MODE_DEBUG ON"
	composerFichierSortie ;
	echo "***********************************************************"
	} || {
		sauverFichier "${leFICHIER}"
		MsgBox "fichier sauvé"
		# echo "MODE_DEBUG OFF"
	} 

exit 0

un lanceur
lanceur.sh

#!/bin/bash
# ----------------------------------------------
nomlogiciel="${0##*/}"
FONCTION=""
VERSION="alpha"
# NOTES DE VERSIONS
# ----------------------------------------------
echo "lancement $nomlogiciel..." ;

# FICHIER="" 
# cp $FICHIER "test.csv" 

FICHIER="test.csv"
AJOUT="ce texte à été ajouté"
INSERT="ce texte a été insérer"
REMPLACE="ce texte remplace la ligne d'origine"
ECHANGE="1 3"

# un par un
# ./reader.sh -f="$FICHIER" -a="${AJOUT}"
# ./reader.sh -f="$FICHIER" -i="5 ${INSERT}"
# ./reader.sh -f="$FICHIER" -r="7 ${REMPLACE}"
# ./reader.sh -f="$FICHIER" -e="${ECHANGE}" ;

# en une seule passe
./reader.sh -f="$FICHIER" -a="${AJOUT}" -i="5 ${INSERT}" -r="7 ${REMPLACE}" -e="${ECHANGE}" ;

exit 0

le fichier modifié devient :

0|un nom|une réf|une date|valeur|valeur1|valeur2|valeur3|valeur4
3|kjfkj||||||||
2|gdfgdgf|7dgd456|jygjkg|'zaeaze'|'plein de quote"|et encore|45|67|45
1|machine|7,456|'titi'|01/01/2010|45|67|45|67|45
4|gdfgdgf|7dgd456|jygjkg|zaeaze|"encore du texte"|et encore|45|67|45
ce texte a été insérer
5|tete|123,12346|titi|20/03/2017|100|200|300|400|500 600
ce texte remplace la ligne d'origine
7|leu set...
ce texte à été ajouté

En ligne

#2 Le 23/03/2017, à 11:59

kholo

Re : [TUTO - BASH] parser un fichier texte : ajout supp insert échange

reader.sh un peu nettoyé
fonction d'édition ajoutée : -l (l pour lister)

#!/bin/bash
# ----------------------------------------------
# nomlogiciel="${0##*/}"
FONCTION="charge un fichier texte ligne par ligne dans un tableau
permet des actions sur ce fichier :
ajouter, insérer, supprimer, remplacer, lister"
VERSION="0.003"
# NOTES DE VERSIONS
# kholo
# https://forum.ubuntu-fr.org/viewtopic.php?pid=21700983
# ----------------------------------------------

# décommenter pour activer
# MODE_DEBUG=1

function MsgBox () { # texte
	zenity --info --text="$@" ;
	}

function infos () {
echo "Aucun argument à votre demande
${0##*/} 
${FONCTION}

Utilisation :
$0 -f fichier [-a-i-s-r-e] OPTIONS
$0 -f fichier1 [-x] fichier2

a) ajouter Ligne
	-a texte_à_ajouter
i) inserer Ligne
	-i numéro texte_à_insérer
s) supprimer Ligne
	-s numéro_Ligne
r) remplacer Ligne
	-r numéro texte_à_ajouter
e) echanger Ligne1 par Ligne2
	-e numéro numéro
l) liste une ligne
	-l numéro numéro
x) executerFichierScript
pas encore codé
	-x fichier
"
exit 1
}


# manque arguments informations
[[ ${#@} -lt 1 ]] && infos
# [[ ${#@} -lt 1 ]] || echo -e "argument passés : \n$@\n"
# [[ -n "$@" ]] && MsgBox "$@" || infos

# ----------------------------------------------
leFICHIER="" ; 

# TODO gestion de la modification et enregistrement éventuel du fichier
# set / unset !
# MODIFIE=0

# ToutesLesLignes
declare -a ToutesLesLignes ; # ToutesLesLignes=[] ;

numLigneCourante=0 ; 
declare -a txtLigneCourante ; # txtLigneCourante=[] ;

declare -a txtTemp ; # txtTemp=[] ;
declare -a tete ; # tete=[] ;

function chargerFichierDanslesLignes () { # fichier : /dossier/mon_fichier.extension
	IFS=$'\n' ;
	local leTexte="$(cat "${@}")" ;
	ToutesLesLignes=( $leTexte ) ;
	}

# ----------------------------------------------
# -a 
function ajouterLigne () { # texte à ajouter au tableau
	ToutesLesLignes[${#ToutesLesLignes[@]}]="$@" ;
	# ou
	# ToutesLesLignes=( ${ToutesLesLignes[@]} "$@" ) ;
	}
# -i 
function insererUneLigne () { # "n° texte à insérer"
	local a=${@%% *}
	local b=${@#* }
	local arr=()

	for ((i=0;i<${a};i++)); do
		arr+=(${ToutesLesLignes[$i]}) 
	done
	arr+=($b) 
	for ((i=${a};i<=$(expr ${#ToutesLesLignes[@]} - 1);i++)); do
		arr+=(${ToutesLesLignes[$i]}) 
	done

	ToutesLesLignes=(${arr[@]})
	}
# -s 
function supprimerUneLigne () { # par numéro Ligne
	unset ToutesLesLignes[$@] ;
	}
# -r 
function remplacerUneLigne () { # num et texte à ajouter au tableau
	local a=${@%% *}
	local b=${@#* }
	ToutesLesLignes[$a]=""
	ToutesLesLignes+=([$a]="$b") ;
	}
# -e 
function echangerLigne1parLigne2 () {
	local L1
	local L2

	local a=${@%% *}
	local b=${@#* }
	L1="${ToutesLesLignes[$a]}"
	L2="${ToutesLesLignes[$b]}"

	ToutesLesLignes[$b]="$L1"
	ToutesLesLignes[$a]="$L2"
	}
# -l
function listerLigne () {
	echo "${ToutesLesLignes[$@]}"
	}

# ----------------------------------------------
# -c
function executerFichierScript () {
	# echo "TODO executerFichierScript"
	MsgBox "TODO executerFichierScript"
	}

# ----------------------------------------------
function parser_arguments {
case $@ in
	-f=*|--fichier=*)
			leFICHIER="${@#*=}"
			chargerFichierDanslesLignes "${leFICHIER}"
			;;
	-a=*|--ajouterLigne=*) # texte à ajouter au tableau
			ajouterLigne "${@#*=}"
			;;
	-i=*|--insererUneLigne=*) # "n°" "texte à insérer"
			insererUneLigne "${@#*=}"
			;;
	-s=*|--supprimerUneLigne=*) # par numéro Ligne
			supprimerUneLigne "${@#*=}"
			;;
	-r=*|--remplacerUneLigne=*) # num et texte à ajouter au tableau
			remplacerUneLigne "${@#*=}"
			;;
	-e=*|--echangerLigne1parLigne2=*)
			echangerLigne1parLigne2 "${@#*=}"
			;;
	-l=*|--listerLigne=*) # par numéro Ligne
			listerLigne "${@#*=}"
			;;
	-x=*|--executerFichierScript=*)
			executerFichierScript "${@#*=}"
			;;

	-h|-?)
			infos
			exit 1
			;;
	-*)
			# MsgBox "${@#*=}"
			echo "${i} : option invalide : ${@#*=}"
			exit 1
			;;
esac
	}

function reader-arg () {
for i in "$@"
do
	# echo -e "i :\n$i"
	parser_arguments "$i"
done
}
reader-arg "$@"

function composerFichierSortie () {
	local ligneEC
	IFS=$'\n' ;
	for ligneEC in ${ToutesLesLignes[@]}
	do
		echo ${ligneEC} ;
	done
	}

function sauverFichier () {
	composerFichierSortie  | tee "$@" ;
	}

[ $MODE_DEBUG ] && {
		# echo "MODE_DEBUG ON"
		echo "***********************************************************"
		composerFichierSortie ;
		echo "***********************************************************"
	} || {
		# echo "MODE_DEBUG OFF"
		# sauverFichier "${leFICHIER}"
		Main_out="$(sauverFichier "${leFICHIER}")"
		# MsgBox "fichier sauvé"
	} 

exit 0

Dernière modification par kholo (Le 23/03/2017, à 12:05)

En ligne

#3 Le 23/03/2017, à 13:06

Watael

Re : [TUTO - BASH] parser un fichier texte : ajout supp insert échange

salut,

il y a une commandepour placer le contenu d'un fichier dans un tableau ligne par ligne : mapfile (tu n'auras plus à modifier l'IFS)

expr est une commande externe inutile : le shell sait faire de l'arithmétique sur les entiers.

un échange de variable se fait avec une seule variable temporaire.

t=a
a=b
b=t

il fait mettre des guillemets autour des variables (les tableaux sont des variables ! tu n'auras plus à modifier l'IFS)

je crois que je n'ai jamais vu d'options courtes (une seule lettre) accompagnée du signe égal pour déclarer un argument...
d'autant que ce n'est pas montré dans la fonction infos.

Dernière modification par Watael (Le 23/03/2017, à 13:12)


eval, c'est mal.

Hors ligne

#4 Le 23/03/2017, à 19:56

kholo

Re : [TUTO - BASH] parser un fichier texte : ajout supp insert échange

bonjour Watael,
merci pour la lecture et le com...

mapfile : je n'ai pas réussi à l'utiliser simplement et intuitivement...
mais je vais rechercher un peu plus
il semble que la version de mapfile de mon 14.04 ne prenne pas le -d pour délimiter
sinon, je trouve le changement de IFS et l'envoie dans une variable avec les parenthèses
super simple à se souvenir pour moi qui ai un petit cerveau !

pour l'échange, j'ai appliqué ta proposition... en effet; j'avais déjà lu ce type d’échange !
la fonction devient :

function echangerLigne1parLigne2 () {
	local a=${@%% *}
	local b=${@#* }

	ToutesLesLignes[t]="${ToutesLesLignes[$a]}"
	ToutesLesLignes[$a]="${ToutesLesLignes[$b]}"
	ToutesLesLignes[$b]="${ToutesLesLignes[t]}"
	}

Pour les arguments, le égale me semblait plus simple
et peut éviter certaines erreurs d'interprétation
mais en te lisant, oui, je peux parser un espace
en attendant j'adapte les infos

function infos () {
echo "Aucun argument à votre demande
${0##*/} 
${FONCTION}

Utilisation :
$0 -f fichier [-a-i-s-r-e]=OPTIONS
$0 -f fichier1 [-x]=fichier2

a) ajouter Ligne
	-a=texte_à_ajouter
i) inserer Ligne
	-i=numéro texte_à_insérer
s) supprimer Ligne
	-s=numéro_Ligne
r) remplacer Ligne
	-r=numéro texte_à_ajouter
e) echanger Ligne1 par Ligne2
	-e=numéro numéro
l) liste une ligne
	-l=numéro numéro
L) liste toutes les lignes
	-L

x) executerFichierScript
pas encore codé
	-x=fichier
"
exit 1
}

je remettrai le code du premier post lors d'une prochaine mise à jour
merci encore !

En ligne

#5 Le 23/03/2017, à 20:59

Watael

Re : [TUTO - BASH] parser un fichier texte : ajout supp insert échange

pourquoi vouloir utiliser l'option -d de mapfile ?
comme pour read, ce n'est utile que si tu veux utiliser un autre délimiteur de fin de ligne que le retour à la ligne.

function echangerLigne1parLigne2 () {
	local a=$1
	local b=$2
# on peut se passer de ses deux variables

	t="${ToutesLesLignes[$a]}"
	ToutesLesLignes[$a]="${ToutesLesLignes[$b]}"
	ToutesLesLignes[$b]="$t"
	}

apparemment, tu as un peu de mal aevc les arguments des fonction : ça fonctionne comme les arguments d'un script.

$ myCaller() { read -a args <<<"$@"; printf '%s\n' "${args[@]}"; maFonction "${args[@]:1}";}
$ maFonction () { echo "\$2 = $2";} 
$ myCaller -e mlk poi
-e
mlk
poi
$2 = poi

et encore, ça pourrait être bien plus simple.
àmha, le signe égal pose plus de problème qu'il n'améliore les choses.

et puis, il y a getopts pour gérer les options d'un script, qui ne gère ques les options courtes par défaut, mais j'ai vu qu'il est possible de gérer aussi des options longues.
sinon, la commande externe getopt, elle, gère nativement les options longues.

Dernière modification par Watael (Le 23/03/2017, à 22:57)


eval, c'est mal.

Hors ligne

#6 Le 06/04/2017, à 12:44

kholo

Re : [TUTO - BASH] parser un fichier texte : ajout supp insert échange

salut Watael,
désolé de ne pas être repassé ici plus tôt...
je fais toujours trop de choses en même temps !
pour aller plus loin et après avoir recherché, je trouve getop lourdingue
en fait une fois qu'on maîtrise le changement de IFS et les tableaux c'est presque simple
(pour un vieux inculte comme moi !)

donc j'ai avancé, je met une version ici
c'est juste pour laisser une trace car ya plein de déchets...

reader.sh

#!/bin/bash
# ----------------------------------------------
# nomlogiciel="${0##*/}"
FONCTION="charge un fichier texte ligne par ligne dans un tableau
qui commence par la ligne 0
permet des actions sur ce fichier :
ajouter, insérer, supprimer, remplacer, lister,...

csv séparé et ligne d'en tête pour les noms de champs
ATTENTION le séparateur doit finir la première ligne
rechercher dans toutes les colonnes et renvoie les coordonnées : ligne,colonne,
rechercher dans une colonne en partilulier, renverra le numéro de ligne.
"
VERSION="0.011"
# NOTES DE VERSIONS
# kholo
# https://forum.ubuntu-fr.org/viewtopic.php?pid=21700983
# ----------------------------------------------

# décommenter pour activer
# MODE_DEBUG=1

function MsgBox () { # texte
	zenity --info --text="$@" ;
	}
function infos () {
local FICHIER="test.csv"
local AJOUT="ce texte a été ajouté"
local INSERT="ce texte a été inséré"
local REMPLACE="ce texte remplace la ligne d'origine"
local ECHANGE="1 3"
local RECHERCHE="nom"

echo "Aucun argument à votre demande
----------------------------------------------
${0##*/} 
${FONCTION}

----------------------------------------------
Utilisation :
$0 -f=fichier [-a-i-s-r-e]=OPTIONS
$0 -f=fichier1 -x=fichier2

a) ajouter Ligne
	-a=texte_à_ajouter
i) inserer Ligne
	-i=numéro texte_à_insérer
s) supprimer Ligne
	-s=numéro_Ligne
r) remplacer Ligne
	-r=numéro texte_à_ajouter
e) echanger Ligne1 par Ligne2
	-e=numéro numéro
l) liste une ligne
	-l=numéro numéro
L) liste toutes les lignes
	-L

x) executerFichierScript
pas encore codé
	-x=fichier
	
----------------------------------------------
Exemples : 
liste de toutes les lignes
$0 -f=\"$FICHIER\" -L ;
afficher la ligne 0
$0 -f=\"$FICHIER\" -l=0 ;
afficher la ligne 5 (depuis la ligne 0)
$0 -f=\"$FICHIER\" -l=5 ;
...
----------------------------------------------
Séries :
un par un
ajouter ${AJOUT}
$0 -f=\"$FICHIER\" -a=\"${AJOUT}\" ;
insérer ${INSERT} à la ligne 5 (depuis la ligne 0)
$0 -f=\"$FICHIER\" -i=\"5 ${INSERT}\" ;
remplacer la ligne 7 (depuis 0) par ${REMPLACE}
$0 -f=\"$FICHIER\" -r=\"7 ${REMPLACE}\" ;
échanger les lignes ${ECHANGE}
$0 -f=\"$FICHIER\" -e=\"${ECHANGE}\" ;
----------------------------------------------

voir les lignes 5, 7 et 9
$0 -f=\"$FICHIER\" -l=5 -l=7 -l=9 ;
supprimer les lignes 5, 7 et 9
$0 -f=\"$FICHIER\" -s=5 -s=7 -s=9 ;
----------------------------------------------
en une seule passe
$0 -f=\"$FICHIER\" -a=\"${AJOUT}\" \
-i=\"5 ${INSERT}\" -r=\"7 ${REMPLACE}\" -e=\"${ECHANGE}\" \
-l=5 -l=7 -l=9 -s=5 -s=7 -s=9 ;

Rechercher :

$0 -f=\"$FICHIER\" -RR=\"${RECHERCHE}\"
retour sera
numéro_de_ligne,numéro_de_colonne

$0 -f=\"$FICHIER\" -R=\"5 ${RECHERCHE}\"
retour sera
numéro_de_ligne

$0 -f=\"$FICHIER\" -R=\"6 ${RECHERCHE}\"

...
-g : getLigne num # idem listerLigne -l
-G : getLigneColonne num num

"
}

# function nbreElements () {
# 
	# }

# manque arguments informations
[[ ${#@} -lt 1 ]] && {
	infos ; 
	exit 1
	}
# ----------------------------------------------
leFICHIER="" ; 
#gestion de la modification et enregistrement éventuel du fichier
MODIFIE=0
#ToutesLesLignes
declare -a ToutesLesLignes ; # ToutesLesLignes=[] ;
#LigneCourante
numLigneCourante=0 ; 
declare -a txtLigneCourante ; # txtLigneCourante=[] ;
#declare -a txtTemp ; # txtTemp=[] ;
#declare -a EnTete ; # EnTete=[] ;
EnTete=""
nbreChamps=""

# ----------------------------------------------
function chargerFichierDanslesLignes () { # fichier : /dossier/mon_fichier.extension
	# IFS=$'\n' ;
	# local leTexte="$(cat "${@}")" ;
	# ToutesLesLignes=( $leTexte ) ;
	IFS=$'\n' ToutesLesLignes=( $(cat "${@}") ) ;
	}
# ----------------------------------------------
function ajouterUneLigne () { # texte à ajouter au tableau
# -a 
	ToutesLesLignes[${#ToutesLesLignes[@]}]="$@" ;
	# ou
	# ToutesLesLignes=( ${ToutesLesLignes[@]} "$@" ) ;
	}
function insererUneLigne () { # "n° texte à insérer"
# -i 
	local a=${@%% *}
	local b=${@#* }

# MsgBox "
# a=${@%% *}
# b=${@#* }
# "

	# nbres=("$@")
	# a="${nbres[0]}"
	# b="${nbres[1]}"
	
IFS=$'\n' ;
	local arr=()

	for ((i=0;i<${a};i++)); do
		arr+=(${ToutesLesLignes[$i]}) 
		# arr=(${ToutesLesLignes[$i]}) 
	done
	arr+=($b)
	for ((i=${a};i<=$(expr ${#ToutesLesLignes[@]} - 1);i++)); do
	# for ((i=${a};i<=${#ToutesLesLignes[@]} - 1;i++)); do
		arr+=(${ToutesLesLignes[$i]}) 
	done

	ToutesLesLignes=(${arr[@]})
	}
function supprimerUneLigne () { # par numéro Ligne
# -s 
	unset ToutesLesLignes[$@] ;
	}
function remplacerUneLigne () { # num et texte à ajouter au tableau
# -r 
	local a=${@%% *}
	local b=${@#* }
	# nbres=("$@")
	# a="${nbres[0]}"
	# b="${nbres[1]}"

	ToutesLesLignes[$a]=""
	ToutesLesLignes+=([$a]="$b") ;
	}
function echangerLigne1parLigne2 () { # num num 
# -e 
	local L1
	local L2
	local a=${@%% *}
	local b=${@#* }
	# MsgBox "ici \na=$a \nb=$b"
	L1="${ToutesLesLignes[$a]}"
	L2="${ToutesLesLignes[$b]}"
	#ToutesLesLignes[$b]=""
	#ToutesLesLignes[$a]=""
	ToutesLesLignes[$b]="$L1"
	ToutesLesLignes[$a]="$L2"
	}
function listerLigne () { # num
# -l
	echo "${ToutesLesLignes[$@]}"
	# MsgBox "listerLigne"
	}
function listerToutesLesLignes () {
# -L
	# printf '%s\n' "${ToutesLesLignes[@]}"
	#echo "${ToutesLesLignes[@]}" # ???
	# OLD
	local ligneEC
	IFS=$'\n' ;
	for ligneEC in ${ToutesLesLignes[@]}
	do
		echo ${ligneEC} ;
	done
	}
# ----------------------------------------------
function ajouterUneColonne () {
	MsgBox "TODO ajouterUneColonne"
	local uneligne
	local x=0
	IFS=$'\n' ;
	for uneligne in ${ToutesLesLignes[@]}
	do
		echo ${uneligne} ;
		# ToutesLesLignes[$x]+="$leSEPARATOR"
		# ToutesLesLignes[$x]+="$@"
		ToutesLesLignes[$x]+="$leSEPARATOR"
		((x++))
	done
	ToutesLesLignes[0]+="$@"
	}
function insererUneColonne () { # num texte_enTete
	MsgBox "TODO insererUneColonne"
	local i=${@%% *}
	local duTEXTE=${@#* }
	local uneligne
	local x=0
	IFS=$'\n' ;
	for uneligne in ${ToutesLesLignes[@]}
	do
		# echo "${uneligne}" ;
		IFS=$leSEPARATOR lesColonnes=( $uneligne )
		lesColonnes=( [$i]="$duTEXTE" )
		
		ToutesLesLignes[$x]="$(IFS="$leSEPARATOR" echo "${lesColonnes[*]}" ;)"
		((x++))
	done
	ToutesLesLignes[0]+="$@"
	}
function supprimerUneColonne () { # num
	MsgBox "TODO supprimerUneColonne"
	local numCol=${@}

	local uneligne
	local x=0
	IFS=$'\n' ;
	for uneligne in ${ToutesLesLignes[@]}
	do
		#echo "${uneligne}" ;
		IFS=$leSEPARATOR lesColonnes=( $uneligne )
		unset lesColonnes[$i]
		ToutesLesLignes[$x]="$(IFS="$leSEPARATOR" echo "${lesColonnes[*]}" ;)"
		((x++))
	done
	ToutesLesLignes[0]+="$@"
	}
function echangerColonne1par2 () { # num num
	MsgBox "TODO deplacerUneColonne"
	# local numCol=${@}
	local i=${@%% *}
	local j=${@#* }

	local uneligne
	local x=0
	IFS=$'\n' ;
	for uneligne in ${ToutesLesLignes[@]}
	do
		# echo "${uneligne}" ;
		IFS=$leSEPARATOR lesColonnes=( $uneligne )
		t="${lesColonnes[$i]}"
		# unset lesColonnes[$i]
		lesColonnes[$i]="${lesColonnes[$j]}"
		lesColonnes[$j]="${t}"
		ToutesLesLignes[$x]="$(IFS="$leSEPARATOR" echo "${lesColonnes[*]}" ;)"
		((x++))
	done
	ToutesLesLignes[0]+="$@"
	}

# ----------------------------------------------
function rechercherDansToutesLesColonnes () { # texte à rechercher
# -RR
	local RECHERCHE=$@
	TROUVE=0
	# MsgBox "RECHERCHE : ${RECHERCHE}"
	x=0
	IFS=$'\n' ;
	for uneLigne in ${ToutesLesLignes[@]}
	do
		echo "$uneLigne" | grep "${RECHERCHE}" >/dev/null && {
		# echo "$uneLigne" | grep "${RECHERCHE}" && {
		IFS="$leSEPARATOR" ligne=( $uneLigne )
		i=0
		# MsgBox "nbreChamps : ${nbreChamps}"
		while [ $i -le $((nbreChamps-1)) ]; 
		do
			# MsgBox "Champ : $i ${ligne[$i]}"
			echo "${ligne[$i]}" | grep "${RECHERCHE}" >/dev/null && {
			# echo "${ligne[$i]}" | grep "${RECHERCHE}" && {
				# echo "Ligne $x colonne $i"
				TROUVE=1
				echo "$x $i"
			}
			((i++))
		done 
		}
		((x++))
	done
	[ $TROUVE = 0 ] && echo "-1" #|| echo "oui TEST"
	}
function rechercherDansColonne () { # num et texte à rechercher
# -R
	local i=${@%% *}
	local RECHERCHE=${@#* }
	# MsgBox "RECHERCHE dans colonne $i : ${RECHERCHE}"
	# local i=$1
	# shift
	# local RECHERCHE=$@

	TROUVE=0
	x=0
	IFS=$'\n' ;
	for uneLigne in ${ToutesLesLignes[@]}
	do
		IFS="$leSEPARATOR" ligne=( $uneLigne )
		echo "${ligne[$i]}" | grep "${RECHERCHE}" >/dev/null && {
			TROUVE=1
			echo "$x"
			}
		((x++))
	done
	[ $TROUVE = 0 ] && echo "-1" #|| echo "oui TEST"
	}
function getLigneColonne () {
# -G
	local L
	local C
	local laLigne
	local laColonne

	let "L=${@%% *}"
	let "C=${@#* }"

	IFS="$leSEPARATOR" laLigne=(${ToutesLesLignes[$L]})
	laColonne="${laLigne[$C]}"

	echo "${laColonne}"
	}

# ----------------------------------------------
function executerFichierScript () {
# -c
	# echo "TODO executerFichierScript"
	MsgBox "TODO executerFichierScript"
	}
# ----------------------------------------------
# ----------------------------------------------
function supprimerEspacesFinVariable () {
	local EnTete="$@"
	while [[ ${EnTete: -2:1} = " " ]]; do
		EnTete="${EnTete:0:(( ${#EnTete} - 1 ))}"
	done
	echo "$EnTete"
	}
function donnerDernierCaractere () {
	echo ${leTexte: -2:1}
	}
function chargerEnTete () {
	EnTete=${ToutesLesLignes[0]}
	EnTete="$(supprimerEspacesFinVariable "$EnTete")"
	# echo -e "EnTete : ${#EnTete} crtrs \nEnTete=${EnTete}"
	leSEPARATOR="${EnTete: -2:1}"
	# leSEPARATOR="${EnTete: -2}"
	IFS="$leSEPARATOR" EnTete=( ${EnTete} )
	# echo "${EnTete}"
	let "nbreChamps=${#EnTete[@]}"
	((nbreChamps--))
	# echo "on a $nbreChamps Champs"
	}
# function chargerSeparator () {
	# }
function chargerANNEXES () {
	chargerEnTete
	# echo "${EnTete}"
	# chargerSeparator
	# echo "leSEPARATOR : $leSEPARATOR"
	}
# ----------------------------------------------
function parser_arguments {
case $@ in
	-f=*|--fichier=*)
		leFICHIER="${@#*=}"
		chargerFichierDanslesLignes "${leFICHIER}"
		chargerANNEXES ;
		MODIFIE=0 ;;
	-a=*|--ajouterUneLigne=*) # texte à ajouter au tableau
		ajouterUneLigne "${@#*=}"
		MODIFIE=1 ;;
	-A=*|--ajouterUneColonne=*) # texte à ajouter au tableau
		ajouterUneColonne "${@#*=}"
		MODIFIE=1 ;;
	-i=*|--insererUneLigne=*) # "n°" "texte à insérer"
		insererUneLigne "${@#*=}"
		MODIFIE=1 ;;
	-I=*|--insererUneColonne=*) # "n°" "texte à insérer" (enTete)
		insererUneColonne "${@#*=}"
		MODIFIE=1 ;;
	-s=*|--supprimerUneLigne=*) # par numéro Ligne
		supprimerUneLigne "${@#*=}"
		MODIFIE=1 ;;
	-S=*|--supprimerUneColonne=*) # par numéro Ligne
		supprimerUneColonne "${@#*=}"
		MODIFIE=1 ;;
	-r=*|--remplacerUneLigne=*) # num et texte à ajouter au tableau
		remplacerUneLigne "${@#*=}"
		MODIFIE=1 ;;
	-e=*|--echangerLigne1parLigne2=*) # num num 
		echangerLigne1parLigne2 "${@#*=}"
		MODIFIE=1 ;;
	-E=*|--echangerColonne1par2=*) # num num 
		echangerColonne1par2 "${@#*=}"
		MODIFIE=1 ;;
	-l=*|--listerLigne=*) # par numéro Ligne
		listerLigne "${@#*=}" ;;
	-L|--listerToutesLesLignes) # toutes les lignes
		listerToutesLesLignes ;;
	-RR=*|--rechercherDansToutesLesColonnes=*) # texte à rechercher
		rechercherDansToutesLesColonnes "${@#*=}" ;;
	-R=*|--rechercherDansColonne=*) # num et texte à rechercher
		rechercherDansColonne "${@#*=}" ;;
	-g=*|--getLigne=*) # num 
		listerLigne "${@#*=}" ;;
	-G=*|--getLigneColonne=*) # num num 
		getLigneColonne "${@#*=}" ;;

	-x=*|--executerFichierScript=*)
		executerFichierScript "${@#*=}" ;;

	-h|-?)
		infos
		exit 1
		;;
	-*)
		# MsgBox "${@#*=}"
		echo "${i} : option invalide : ${@#*=}"
		exit 1
		;;
esac
	}
function reader-arg () {
	for i in "$@"; do
		# echo "arg : $i"
		parser_arguments "$i"
	done
	}
reader-arg "$@"
function composerFichierSortie () {
	local ligneEC
	IFS=$'\n' ;
	for ligneEC in ${ToutesLesLignes[@]}; do
		echo ${ligneEC} ;
	done
	}
function sauverFichier () {
	composerFichierSortie  | tee "$@"  >/dev/null ;
	}

# MsgBox "modifié ?\n$MODIFIE"
[ $MODE_DEBUG ] && {
	echo -e "***********************************************************\nMODE_DEBUG ON"
	composerFichierSortie
	# sauverFichier "${leFICHIER}.test"
	# gedit "${leFICHIER}.test" &
	echo "***********************************************************"
} || {
	[ $MODIFIE -eq 1 ] && {
		sauverFichier "${leFICHIER}"
		# MsgBox "fichier sauvé"
	} 
} 

exit 0

et le lanceur pour test :

#!/bin/bash
# ----------------------------------------------
nomlogiciel="${0##*/}"
FONCTION=""
VERSION="0.002"
# NOTES DE VERSIONS
# ----------------------------------------------
# echo "lancement $nomlogiciel..." ;

# function initialization () {

# leFICHIER
# leFICHIER="data/contact_utf8.csv"
# leFICHIER="data/20170223/1"
# leFICHIER="data/bq.csv"
# leFICHIER="data/liste.csv"
leFICHIER="test.csv"

echo "0|un nom|une réf|une date|valeur|valeur1|valeur2|valeur3|valeur4|
1|machine|7,456|'titi'|01/01/2010|45|67|45|67|45
2|gdfgdgf|7dgd456|jygjkg|'zaeaze'|'plein de quote\"|et encore|45|67|45
3|kjfkj||||||||
4|gdfgdgf|7dgd456|jygjkg|zaeaze|\"encore du texte\"|et encore|45|67|45
5|tete|123,12346|titi|20/03/2017|100|200|300|400|500 600
6|poiuytr|4679|nini|10/04/2021|un nom|un autre|le troise|leu cat|et de cinq
7|leu set...
" | tee ${leFICHIER} >/dev/null 


READER="reader.sh"
# READER="reader (0.007).sh"
# READER="reader (0.005).sh"

AJOUT="ce texte a été ajouté"
INSERT="ce texte a été inséré"
REMPLACE="ce texte remplace la ligne d'origine"
ECHANGE="1 3"
	# }

# compteur de temps
heuredebut=""
heurefin=""
function debut () {
	heuredebut=$(date +%s)
	}
function fin () {
	heurefin=$(date +%s)
	compterTemps
	}
function compterTemps () {
# mettre au début
# heuredebut=$(date +%s)
# mettre à la fin
# heurefin=$(date +%s)

DIFF=$(($heurefin - $heuredebut))
HEURES=$(($DIFF / 3600))
DIFF=$(($DIFF-($HEURES*3600)))
MINUTES=$(($DIFF / 60))
SECONDES=$(($DIFF % 60))

# echo "date : $(date)
# heuredebut	: $heuredebut
# heurefin	: $heurefin
# DIFF : $DIFF
# Il s'est passé
# "
echo "$HEURES h $MINUTES m $SECONDES sec"
	}

function supprimerLesQuotes () { # texte
	echo ${@//'"'/} ;
	}
function MsgBox () { # texte
	zenity --info --text="$@" ;
	}
function fichierEnUTF8 () {
	local infos=$(file -i "$@")
	case ${infos} in
		*'charset=utf-8'* ) 
			# echo "c'est de l'utf8"
			;;
		*'charset=iso-8859-1'* ) 
			# echo "à convertir !!!"
			# echo "$var" | iconv --from-code=utf-8 --to-code=utf-16le --output=file2.txt
			local txt_leFICHIER="${leFICHIER%.*}" ;
			local txt_bak="${txt_leFICHIER}.bak" ;
			cp --backup=numbered "$leFICHIER" "$txt_bak" ;
			iconv -f 'iso-8859-1' -t utf-8 "$txt_bak" > "$leFICHIER"
			MsgBox "fichier converti en utf8 \nOriginal sauvegardé en \n$txt_bak"
			;;
		* )
			MsgBox "${infos[2]} \nkézako ?"
			;;
	esac
	}
function _quitter {
# journal "_quitter"
# mettre ici tout ce qui sera nescessaire à la bonne fermeture

	exit 0
}

function CREER_MAIN_DIALOG () {
local laLIST="$(echo -e "$@" | while read line; do 
echo "<item>${line}</item>" ;
done)" ;

export MAIN_DIALOG="
<vbox>
	<hbox>
		<text>
			<label>Choisir un élément dans la liste :</label>
		</text>
		<combobox>
			<variable>COMBOBOX</variable>
			${laLIST}
		</combobox>
	</hbox>
	<hbox>
		<button ok></button>
		<button cancel></button>
	</hbox>
</vbox>
" ;

	}
function choisirFichier () {
# laLIST="$(ls -A data/*.csv)"
CREER_MAIN_DIALOG "$(ls -A data/*.csv)"

IFS=$'\n' ;
local out="$(gtkdialog --program=MAIN_DIALOG)" ;
local selection="$(echo -e "$out" | grep "COMBOBOX")" ;

out="$(echo -e "$out" | grep "EXIT")" ;
out="${out##*=}" ;

case $out in
	'"OK"' )
				leFICHIER="${PWD}/$(supprimerLesQuotes ${selection##*=})"
				;;
	* ) 		exit 1
				;;
esac
	}
function TEST () {
# LISTdesFichiers () {
# ls -A data/*.csv | while read line; do 
# echo "<item>${line}</item>" ;
# done
# }# laLIST="$(LISTdesFichiers)" ;
local laLIST="$(ls -A data/*.csv | while read line; do 
echo "<item>${line}</item>" ;
done)" ;

export MAIN_DIALOG="
<vbox>
	<hbox>
		<text>
			<label>Combobox:</label>
		</text>
		<combobox>
			<variable>COMBOBOX</variable>
			${laLIST}
		</combobox>
	</hbox>
	<hbox>
		<button ok></button>
		<button cancel></button>
	</hbox>
</vbox>
" ;

IFS=$'\n' ;
local out="$(gtkdialog --program=MAIN_DIALOG)" ;
local unFichier="$(echo -e "$out" | grep "COMBOBOX")" ;

out="$(echo -e "$out" | grep "EXIT")" ;
out="${out##*=}" ;

case $out in
	'"OK"' )	echo "$leFICHIER" ;
				leFICHIER="${PWD}/$(supprimerLesQuotes ${unFichier##*=})"
				;;
	* ) 		exit 1
				;;
esac
	}
function _mainOuvrir () {
	# echo "Appuyer sur une touche pour continuer"
	# read r 
	[ -z "$leFICHIER" ] && choisirFichier ;
	[ -e "$leFICHIER" ] \
	|| {
		echo "pas de leFICHIER ; $leFICHIER" ;
		exit 100
		} \
	&& {
		fichierEnUTF8 ${leFICHIER} ;
		# chargerFichierDanslesLignes ${leFICHIER}
		} ;

	cp ${leFICHIER} "test.csv" 
	}

function AJOUTER () {
echo "AJOUT"
debut
./"${READER}" -f="${leFICHIER}" -a="${AJOUT}"
# echo $?
fin
}
function INSERER () {
echo "INSERT"
debut
./"${READER}" -f="${leFICHIER}" -i="5 ${INSERT}"
# echo $?
fin
}
function REMPLACER () {
echo "REMPLACE"
debut
./"${READER}" -f="${leFICHIER}" -r="7 ${REMPLACE}"
# echo $?
fin
}
function ECHANGER () {
echo "ECHANGE"
debut
./"${READER}" -f="${leFICHIER}" -e="${ECHANGE}" ;
# echo $?
fin
}
function LISTER () {
#clear
echo "--------------------------------------"
./"${READER}" -f="${leFICHIER}" -L
echo "--------------------------------------"
./"${READER}" -f="${leFICHIER}" -l=0
echo "--------------------------------------"
./"${READER}" -f="${leFICHIER}" -l=5
echo "--------------------------------------"

}
function SUPPRIMER () {
echo "ces lignes vont être supprimées"
./"${READER}" -f="${leFICHIER}" -l=5 -l=7 -l=9

./"${READER}" -f="${leFICHIER}" -s=5 -s=7 -s=9

}
function RECHERCHER () {
echo "Rechercher :"
Rechercher='MULTARI'
echo "Rechercher : ${Rechercher} colonne unique"
debut
echo "dans 0"
./"${READER}" -f="${leFICHIER}" -R="0 ${Rechercher}"
echo "dans 1"
./"${READER}" -f="${leFICHIER}" -R="1 ${Rechercher}"
echo "dans 2"
./"${READER}" -f="${leFICHIER}" -R="2 ${Rechercher}"
echo "dans 3"
./"${READER}" -f="${leFICHIER}" -R="3 ${Rechercher}" 
fin

Rechercher="MULTARI"
echo "Rechercher : ${Rechercher}  toutes les colonnes"
debut
./"${READER}" -f="${leFICHIER}" -RR="${Rechercher}"
echo ""
fin

debut
resultat=$(./"${READER}" -f="${leFICHIER}" -RR="${Rechercher}")
IFS=$'\n' resultat=($resultat)

# [ ${resultat} -lt 0 ] && echo "-lt 0" || echo "continue"
[ ${resultat} -lt 0 ] &&  echo "$i" || {
	for i in ${resultat[@]}
	do
		echo "trouvé en $i"
		./"${READER}" -f="${leFICHIER}" -G="${i}"
	done
}
fin
}
function AFFICHER () {
coordonnees='1 1'
echo "Ouvrir coordonnées : ${coordonnees}"
# MsgBox "leFICHIER=${leFICHIER}"
debut
./"${READER}" -f="${leFICHIER}" -G="${coordonnees}"
fin

echo "en une passe :"
debut
val1='1 1'
val2='2 3'
val3='3 4'
val4='5 5'
./"${READER}" -f="${leFICHIER}" -G="${val1}" -G="${val2}" -G="${val3}" -G="${val4}"
fin

debut
val1='1 1'
val2='1 2'
val3='1 3'
val4='1 4'
./"${READER}" -f="${leFICHIER}" -G="${val1}" -G="${val2}" -G="${val3}" -G="${val4}"
fin
}
function MULTIPLE () {
debut
echo "en une seule passe"
./"${READER}" -f="${leFICHIER}" -a="${AJOUT}" -i="5 ${INSERT}" -r="7 ${REMPLACE}" -e="${ECHANGE}" -l=5 -l=7 -l=9 -s=5 -s=7 -s=9;
fin
}

# initialization
_mainOuvrir ;

AJOUTER
INSERER
REMPLACER
ECHANGER
LISTER
SUPPRIMER
RECHERCHER
AFFICHER
MULTIPLE

exit 0

bon, ya encore du taf mais,
faut que je fasse d'autres trucs de temps en temps
sinon je vais prendre la forme de mon siège !

En ligne