2017-10-20 59 views
0

J'ai un problème très étrange avec un script bash, écrit sur une machine Ubuntu 17.04.Bash - si l'instruction ne fonctionne pas automatiquement

Je dispose d'un fichier txt contenant des informations sur les gens de cette façon:

Numéro état de la ville de nom de nom

Avec ces infos, je dois créer un système d'organisation qui fonctionne par l'État. Par exemple, avec une liste comme celle

123 alan smith new_york new_york

123 bob smith buffle new_york

123 Charles Smith Los_Angeles CALIFORNIE

123 smith ALABAMA mobile doyen

le résultat à la fin du calcul devrait être trois nouveaux fichiers nommés NEW_YORK, CALIFORNIA et ALABAMA qui contiennent des gens qui y vivent.

Le script prend en paramètre la liste des noms. J'ai implémenté une instruction if (condition qui est dictée par un test d'existence pour le fichier, juste au cas où il y a plus de personnes vivant dans un certain état) dans une boucle for qui, bizarrement, ne fonctionne que si j'appuie sur enter pendant que le programme est en cours d'exécution. Le résultat est bon, je reçois les fichiers avec les bonnes personnes sur eux, mais il me déroute que je dois appuyer sur Entrée pour faire fonctionner le code, cela n'a pas de sens pour moi.

Voici mon code:

#!/bin/bash 

clear 

#finding how many file lines and adding 1 to use the value as a counter later 
fileLines=`wc -l addresses | cut -f1 --delimiter=" "` 
((fileLines = fileLines+1)) 

for ((i=1; i<$fileLines; i++)) 
do  
    #if the file named as the last column already exists do not create new one 
    test -e `head -n$i | tail -n1 | cut -f5 --delimiter=" "` 
    if [ $? = 0 ] 
    then 
     head -n$i $1 | tail -n1 >> `head -n$i $1 | tail -n1 | cut -f5 --delimiter=" "` 
    else 
     head -n$i $1 | tail -n1 > `head -n$i $1 | tail -n1 | cut -f5 --delimiter=" "` 
    fi 
done 

echo "cancel created files? y/n" 
read key 

if [ $key = y ] 
then 
    rm `ls | grep [A-Z]$` 
    echo "done" 
    read 
else 
    echo "done" 
    read 
fi 

clear 

ce que je fais mal ici? Et d'ailleurs, pourquoi ne me dit-il pas que quelque chose ne va pas?

+3

Votre ligne 'test -e' ne lit pas à partir du fichier. Il lit de vous. Peut-être que vous vouliez 'head -n $ i" $ 1 "' à la place? (Bien que le test ne soit pas nécessaire: vous n'avez pas besoin d'utiliser '>' la première fois, '>>' crée aussi le fichier quand il n'existe pas) –

+0

Cela fonctionne? Comment l'appelez-vous? On dirait qu'il lit stdin, mais ... Voulais-tu juste analyser les lignes par fichier? –

Répondre

0

Le problème immédiat (souligné @that autre gars) est que dans la ligne:

test -e `head -n$i | tail -n1 | cut -f5 --delimiter=" "` 

La commande head n'est pas donné un nom de fichier à lire, il est donc la lecture de stdin (c.-à-vous). Mais je changerais radicalement tout le script, parce que vous le faites d'une manière très inefficace. Si vous avez, par exemple, un fichier de 1000 lignes, vous exécutez head pour lire la première ligne (3 fois, en fait), puis les deux premières lignes (trois fois), puis les trois premières ... au moment où vous êtes fait, head a lu la première ligne du fichier 3000 fois, puis tail l'a rejeté 2997 de ces temps. Vous avez seulement vraiment besoin de le lire une fois.

Lorsque itérer un fichier comme celui-ci, vous êtes beaucoup mieux en train de lire la ligne par ligne fichier, avec quelque chose comme ceci:

while read line; do 
    # process $line here 
done <"$1" 

Mais dans ce cas, il y a un outil encore mieux . awk est vraiment bon traitement des dossiers comme celui-ci, et il peut gérer la tâche vraiment simple:

awk '{ if($5!="") { print $0 >>$5 }}' "$1" 

(Note: Je mets aussi dans le if pour vous assurer qu'il est un cinquième champ/ignore les lignes vides Sans cela. vérifiez qu'il aurait juste été awk '{ print $0 >>$5 }' "$1").

En outre, la commande:

rm `ls | grep [A-Z]$` 

... est une façon vraiment bizarre et fragile de le faire. Parsing la sortie de ls est généralement une mauvaise idée, et encore une fois il y a un moyen beaucoup plus simple de le faire:

rm *[A-Z] 

Enfin, je vous recommande d'utiliser votre script par shellcheck.net, car il pointera quelques autres problèmes (par exemple références variables non cotées).