2010-12-06 4 views
9

J'ai besoin d'obtenir les enregistrements d'un fichier texte sous Unix. Le délimiteur est plusieurs espaces. Par exemple:Unix - Besoin de couper un fichier qui a plusieurs espaces comme délimiteur - awk ou coupé?

2U2133 1239 
1290fsdsf 3234 

De là, je dois extraire

1239 
3234 

Le délimiteur pour tous les enregistrements seront toujours 3 blancs.

Je dois le faire dans un script unix (.scr) et écrire la sortie dans un autre fichier ou l'utiliser comme entrée pour une boucle do-while. J'ai essayé ci-dessous:

while read readline 
do 
     read_int=`echo "$readline"` 
     cnt_exc=`grep "$read_int" ${Directory path}/file1.txt| wc -l` 
if [ $cnt_exc -gt 0 ] 
then 
    int_1=0 
else 
    int_2=0 
fi 
done < awk -F' ' '{ print $2 }' ${Directoty path}/test_file.txt 

test_file.txt est le fichier d'entrée et file1.txt est un fichier de recherche. Mais la méthode ci-dessus ne fonctionne pas et me donne des erreurs de syntaxe près de awk -F

J'ai essayé d'écrire la sortie dans un fichier. Ce qui suit a fonctionné en ligne de commande:

more test_file.txt | awk -F' ' '{ print $2 }' > output.txt 

Cela fonctionne et écrit les enregistrements dans output.txt en ligne de commande. Mais la même commande ne fonctionne pas dans le script unix (c'est un fichier .scr)

Veuillez me faire savoir où je me trompe et comment je peux résoudre ce problème.

Merci,
Visakh

+0

Voir aussi http://stackoverflow.com/questions/7142735/linux-cut-help-how-to-specify-more-spaces-for-the-delimiter – pnkfelix

Répondre

10

Cela dépend de la version ou de l'implémentation de cut sur votre machine. Certaines versions prennent en charge une option, généralement -i, qui signifie «ignorer les champs vides» ou, de manière équivalente, autoriser plusieurs séparateurs entre les champs. Si cela est pris en charge, utilisez:

cut -i -d' ' -f 2 data.file 

Dans le cas contraire (et il est pas universel - et peut-être même pas répandue, puisque ni GNU, ni Mac OS X ont l'option), puis en utilisant awk est meilleur et plus facile à transporter.

Vous devez diriger la sortie de awk dans votre boucle, cependant:

awk -F' ' '{print $2}' ${Directory_path}/test_file.txt | 
while read readline 
do 
    read_int=`echo "$readline"` 
    cnt_exc=`grep "$read_int" ${Directory_path}/file1.txt| wc -l` 
    if [ $cnt_exc -gt 0 ] 
    then int_1=0 
    else int_2=0 
    fi 
done 

Le seul problème résiduel est de savoir si la boucle while est dans un sous-shell et donc de ne pas modifier vos principales variables scripts shell , juste sa propre copie de ces variables.

Avec bash, vous pouvez utiliser process substitution:

while read readline 
do 
    read_int=`echo "$readline"` 
    cnt_exc=`grep "$read_int" ${Directory_path}/file1.txt| wc -l` 
    if [ $cnt_exc -gt 0 ] 
    then int_1=0 
    else int_2=0 
    fi 
done < <(awk -F' ' '{print $2}' ${Directory_path}/test_file.txt) 

Cela laisse la boucle while dans la coquille en cours, mais prend des dispositions pour la sortie de la commande à apparaître comme si d'un fichier.

Le blanc de ${Directory path} n'est normalement pas légal - à moins que ce soit une autre fonctionnalité de Bash que j'ai ratée; vous avez également eu une faute de frappe (Directoty) en un seul endroit.

+0

Merci beaucoup .... tuyauterie de la sortie awk résolu le problème. – visakh

1

En bash, vous pouvez commencer par quelque chose comme ceci:

for n in `${Directoty path}/test_file.txt | cut -d " " -f 4` 
{ 
    grep -c $n ${Directory path}/file*.txt 
} 
0

Il ne fonctionne pas dans le script en raison de la faute de frappe dans « Directo * t * chemin y "(dernière ligne de votre script).

+0

Cela fait partie du problème; le blanc dans le nom n'aide pas non plus. Le reste est que vous devez utiliser plus de notation pour obtenir la sortie d'une commande shell fournie en entrée via la redirection d'E/S plutôt que la tuyauterie. –

3

D'autres façons de faire la même chose, l'erreur dans votre programme est la suivante: Vous ne pouvez pas rediriger de (<) la sortie d'un autre programme. Mettez votre script et l'utiliser un tube comme celui-ci:

awk -F' ' '{ print $2 }' ${Directory path}/test_file.txt | while read readline 

etc.

En outre, l'utilisation de « readline » comme nom de variable peut ou ne peut pas vous avoir des problèmes.

2

Dans ce cas particulier, vous pouvez utiliser la ligne suivante

sed 's/ /\t/g' <file_name> | cut -f 2 

pour obtenir votre deuxième colonnes.

17
cat <file_name> | tr -s ' ' | cut -d ' ' -f 2 
+0

J'aime beaucoup votre réponse, juste parce que l'utilisation de 'tr' et de 'cut' est beaucoup plus élégante qu'une boucle 'awk'. Merci! – valentt

0

Couper n'est pas assez flexible. J'utilise habituellement Perl pour cela:

cat file.txt | perl -F' ' -e 'print $F[1]."\n"' 

Au lieu d'un triple espace après -F vous pouvez mettre une expression régulière Perl. Vous accédez aux champs comme $ F [n], où n est le numéro de champ (le comptage commence à zéro). De cette façon, il n'est pas nécessaire de sed ou tr.

Questions connexes