Je veux faire écho à deux variables sur la même ligne.
Je veux stocker 2015-03-04.01.Abhi_Ram.txt dans une variable FILENAME et 10 dans une variable COUNT et les afficher simultanément.
Sample.txt
2015-03-04.01.Abhi_Ram.txt 10
2015-03-04.02.Abhi_Ram.txt 70
Ci-dessous le code que j'ai créé:
for line in `hadoop fs -cat sample.txt`
do
VAR="${line}"
FILENAME=`echo ${VAR}|awk '{print $1}'`
COUNT=`echo ${VAR}|awk '{print $2}'`
COUNT_DT=`date "+%Y-%m-%d %H:%M:%S"`
echo db"|"Abhi_Ram"|"record_count"|"${FILENAME}"||"${COUNT}"||"${COUNT_DT} >> output.txt
done
I want the output as:
db | Abhi_Ram | record_count | 2015-03-04.01.Abhi_Ram.txt || 10 || timestamp db | Abhi_Ram | record_count | 2015-03-04.02.Abhi_Ram.txt || 70 || timestamp
I'm getting the output as:
db | Abhi_Ram | record_count | 2015-03-04.01.Abhi_Ram.txt |||| horodatage
db | Abhi_Ram | record_count | 10 |||| horodatage
db | Abhi_Ram | record_count | 2015-03-04.02.Abhi_Ram.txt |||| horodatage
db | Abhi_Ram | record_count | 70 |||| horodatage
Est-ce que quelqu'un pourrait me signaler ce qui me manque?
Considérer:
while read filename count
do
count_dt=$(date "+%Y-%m-%d %H:%M:%S")
echo "db|Abhi_Ram|record_count|${filename}||${count}||${count_dt}"
done <sample.txt >>output.txt
Ceci produit le fichier:
$ cat output.txt
db|Abhi_Ram|record_count|2015-03-04.01.Abhi_Ram.json||10||2015-08-10 14:42:39
db|Abhi_Ram|record_count|2015-03-04.02.Abhi_Ram.json||70||2015-08-10 14:42:39
Remarques:
Il est recommandé d’utiliser une casse inférieure ou mixte pour vos variables Shell. Le système utilise des variables majuscules et vous ne voulez pas en écraser une par accident.
Les nombreuses guillemets dans la déclaration echo
étaient inutiles. La totalité de la chaîne de sortie peut être comprise dans une chaîne entre guillemets doubles.
Si vous souhaitez lire un fichier ligne par ligne, il est préférable d’utiliser la construction while read ... done <inputfile
. L'instruction read
nous permet également de définir facilement les variables filename
et count
.
Pour la substitution de commande, beaucoup préfèrent le formulaire $(...)
au formulaire backtick. En effet, (a) la $(...)
différencie visuellement le début et la fin de la substitution de commande, (b) la forme $(...)
s'emboite bien et (c) toutes les polices ne montrent pas clairement les backticks différents des ticks classiques. (Merci Chepner.)
Pour plus d'efficacité, la redirection vers output.txt
a été déplacée à la fin de la boucle. De cette façon, le fichier n'est ouvert et fermé qu'une seule fois. (Merci Charles Duffy.)
Sauf si vous avez besoin que count_dt
soit mis à jour avec chaque entrée individuelle, il peut être placé avant la boucle et défini une seule fois à chaque fois que sample.txt
a été traité. Si vous disposez d'une version à jour de bash (pas de Mac OSX), l'assignation count_dt
peut être remplacée (merci Charles Duffy) par une instruction native bash (aucune suppression requise):
printf -v count_dt '%(%Y-%m-%d %H:%M:%S)T'
John1024 a expliqué comment faire cela correctement; J'aimerais examiner pourquoi la version originale n'a pas fonctionné. Le problème fondamental est que for
fait une boucle sur mots , pas sur des lignes. Le fichier a deux mots sur chaque ligne (un nom de fichier et un compte), de sorte qu'il exécute la boucle deux fois par ligne. Pour voir cela, essayez:
for line in `hadoop fs -cat sample.txt`
do
echo "$line"
done
... et ça va imprimer quelque chose comme:
2015-03-04.01.Abhi_Ram.txt
10
2015-03-04.02.Abhi_Ram.txt
70
... ce que vous ne voulez pas du tout. Il a aussi quelques autres défauts désagréables, comme si le fichier d’entrée contenait le mot "*", il insérerait une liste de noms de fichiers dans le répertoire courant.
L'approche while read ... done <file
est la bonne façon de parcourir des lignes dans un script Shell. Il se trouve que vous pouvez également fractionner chaque ligne en champs sans devoir manipuler awk
(dans ce cas, read filename count
le fait).