2009-09-22 6 views
11

je suis tombé sur le problème suivant: J'écris un script bash Linux qui effectue les opérations suivantes:BASH: caractère de nouvelle ligne bande de chaîne (lecture en ligne)

  • ligne Lire fichier
  • Strip le caractère \n de la fin de la ligne juste lire
  • Exécutez la commande qui est là

Exemple: commands.txt

ls 
ls -l 
ls -ltra 
ps as 

L'exécution du fichier bash devrait obtenir la première ligne, et l'exécuter, mais alors que la présente \n, le shell sorties juste « command not found: ls » Cette partie du script ressemble à ceci

read line 

     if [ -n "$line" ]; then #if not empty line 

       #myline=`echo -n $line | tr -d '\n'` 
       #myline=`echo -e $line | sed ':start /^.*$/N;s/\n//g; t start'` 

       myline=`echo -n $line | tr -d "\n"` 
       $myline #execute it 

       cat $fname | tail -n+2 > $fname.txt 
       mv $fname.txt $fname 
     fi 

J'ai commenté que vous avez les choses que j'ai essayé avant de demander SO. Des solutions? Je briser mon cerveau pour les deux dernières heures au cours de cette ...

+0

vous avez simplement essayé seul '$ de coût média? – knittl

+0

Bien sûr que j'ai fait. Mais il est dit "commande introuvable: ls " –

+0

Tout ce qui est nécessaire est: 'myline =" $ (echo -n "$ line") "' (avec des devers back au lieu de '$()' si vous voulez) – jnylen

Répondre

17

J'aime toujours perl -ne 'chomp and print', pour rogner les nouvelles lignes. Agréable et facile à retenir.

par exemple. ls -l | perl -ne 'chomp and print'

Cependant

Je ne pense pas que votre problème est ici bien. Bien que je ne sois pas sûr de comprendre comment vous passez les commandes du fichier à la 'lecture' dans votre script shell.

Avec un script de test de mon propre comme celui-ci (test.sh)

read line 
if [ -n "$line" ]; then 
    $line 
fi 

et un fichier d'entrée de l'échantillon comme celui-ci (test.cmds)

ls 
ls -l 
ls -ltra 

Si je cours comme ça ./test.sh < test.cmds, je vois le résultat attendu, qui est d'exécuter la première commande 'ls' sur le répertoire de travail en cours.Peut-être que votre fichier d'entrée contient des caractères non imprimables supplémentaires?

mes

ressemble à ceci

od -c test.cmds 
0000000 l s  \n l s  - l \n l s  - l t 
0000020 r a \n              
0000023 

De vos commentaires ci-dessous, je soupçonne que vous pouvez avoir des retours chariot (« \ r ») dans votre fichier d'entrée, ce qui est la même chose que d'une nouvelle ligne. Le fichier d'entrée est-il initialement au format DOS? Si c'est le cas, vous devez convertir la ligne DOS de 2 octets se terminant par "\ r \ n" en un seul octet UNIX, "\ n" pour obtenir les résultats attendus.

Vous devriez pouvoir faire ceci en changeant le "\ n" pour "\ r" dans n'importe laquelle de vos lignes commentées.

+1

J'ai oublié de mentionner que le fichier est écrit à partir de Windows dans un partage samba et j'ai complètement oublié que je devrais rechercher un '\ r 'au lieu de' \ n'. Jusqu'à un vote de moi et merci beaucoup! –

0

mais ne fonctionne pas pour ls, je recommande d'avoir un regard sur find « s 'option -print0

2

J'ai essayé ceci:

read line 
echo -n $line | od -x 

Pour l'entrée 'xxxx', je reçois:

0000000 7878 7878 

Comme vous pouvez le voir, il n'y a \n au fin du contenu de la variable. Je suggère d'exécuter le script avec l'option -x (bash -x script). Cela imprimera toutes les commandes comme elles sont exécutées.

[EDIT] Votre problème est que vous avez édité commands.txt sous Windows. Maintenant, le fichier contient CRLF (0d0a) comme délimiteurs de ligne qui confond read (et ls\r n'est pas une commande connue). Utilisez dos2unix ou similaire pour le transformer en un fichier Unix.

+0

chose est que je ne lis pas à partir du clavier. Je change mon STDIN dans un fichier (le fichier command.txt ci-dessus) et si je fais écho à la ligne $ entre '' Je reçois la sortie '' s ' –

+0

La sortie que je reçois 'echo -n $ line | od -x' est "0000000 736c 000d 0000003" –

+1

Le 0d est un retour chariot. Pas la même chose qu'une nouvelle ligne – cms

1

vous avez besoin commande eval


#!/bin/bash -x 

while read cmd 
do 
if [ "$cmd" ] 
then 
    eval "$cmd" 
fi 
done 

Je l'ai couru comme
./script.sh < file.txt

Et file.txt était:

 
ls 
ls -l 
ls -ltra 
ps as 
+0

'eval' ne fonctionnera pas aussi –

0

Le script suivant fonctionne (au moins pour moi):

#!/bin/bash 

while read I ; do if [ "$I" ] ; then $I ; fi ; done ; 
12

Quelqu'un a déjà écrit un programme qui exécute des commandes shell: fichier sh

Si vous voulez vraiment que pour exécuter la première ligne d'un fichier: head -n 1 file |sh

Si votre problème est retour-chariot: tr -d '\r' <file |sh

+0

Oui, bien sûr, mais cette partie de mon fichier de commandes. C'est plus qu'une simple commande d'exécution à partir du fichier, parce que si c'était juste cela, j'ai utilisé avec certitude seulement 'sh' –

2

vous pouvez également essayer de remplacer les retours chariot avec des sauts de ligne uniquement à l'aide de builtins Bash:

line=$'a line\r' 
line="${line//$'\r'/$'\n'}" 
#line="${line/%$'\r'/$'\n'}"  # replace only at line end 
printf "%s" "$line" | ruby -0777 -n -e 'p $_.to_s' 
Questions connexes