BASH: Striscia carattere nuova linea da stringa (linea di lettura)
Domanda
mi imbattei nel seguente problema: Sto scrivendo uno script bash Linux, che esegue le seguenti operazioni:
- Leggi riga dal file
- Striscia il carattere
\n
dalla fine della linea appena letto - Eseguire il comando che c'è dentro
Esempio: ecommands.txt
ls
ls -l
ls -ltra
ps as
L'esecuzione del file bash dovrebbe ottenere la prima riga, ed eseguirlo, ma mentre la \n
presente, il guscio appena uscite "comando non trovato: ls"
Quella parte dello script simile a questo
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
Commentate avete le cose che ho provato prima di chiedere SO. Eventuali soluzioni? Sto distruggendo il mio cervello per l'ultimo paio di ore su questo ...
Soluzione
mi piace sempre perl -ne 'chomp and print'
, per il taglio a capo. Bello e facile da ricordare.
es. ls -l | perl -ne 'chomp and print'
Tuttavia
Non credo che sia il problema qui però. Anche se non sono sicuro di aver capito come si sta passando i comandi nel file attraverso la 'lettura' nel vostro script di shell.
Con uno script di test della mia come questo (test.sh)
read line
if [ -n "$line" ]; then
$line
fi
e un file di input di esempio come questo (test.cmds)
ls
ls -l
ls -ltra
Se corro come questo ./test.sh < test.cmds
, vedo il risultato atteso, che è quello di eseguire il 'ls' primo comando nella directory di lavoro corrente.
Forse il vostro file di input ha caratteri non stampabili supplementari in esso?
miniera assomiglia a questo
od -c test.cmds
0000000 l s \n l s - l \n l s - l t
0000020 r a \n
0000023
Da vostri commenti qui sotto, ho il sospetto si può avere ritorni a capo ( "\ r") nel file di input, che non è la stessa cosa di un ritorno a capo. È il file di input originariamente in formato DOS? Se è così, allora avete bisogno di convertire la linea di DOS 2 byte finale "\ r \ n" al singolo byte UNIX uno, "\ n" per ottenere i risultati attesi.
Si dovrebbe essere in grado di fare questo scambiando il "\ n" per "\ r" in uno dei tuoi righe di commento fuori.
Altri suggerimenti
Qualcuno ha già scritto un programma che esegue comandi di shell: file di sh
Se davvero desidera solo per eseguire la prima riga di un file: head -n 1 file |sh
Se il problema è a capo-rendimenti: tr -d '\r' <file |sh
Ho provato questo:
read line
echo -n $line | od -x
Per l'ingresso 'xxxx', ottengo:
0000000 7878 7878
Come si può vedere, non v'è alcuna \n
alla fine del contenuto della variabile. Vi suggerisco di eseguire lo script con l'opzione -x
(bash -x script
). Questo stamperà tutti i comandi mentre vengono eseguiti.
[EDIT] Il tuo problema è che si è modificato ecommands.txt su Windows. Ora, il file contiene CRLF (0d0a) come delimitatori di linea che confonde read
(e ls\r
non è un comando noto). Utilizzare dos2unix
o simili a trasformarlo in un file Unix.
Si può anche provare a sostituire ritorni a capo con a capo solo utilizzando builtin 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'
è necessario il comando eval
#!/bin/bash -x
while read cmd
do
if [ "$cmd" ]
then
eval "$cmd"
fi
done
ho eseguito come E file.txt era:
./script.sh ls
ls -l
ls -ltra
ps as
anche se non lavorare per ls
, vi consiglio di dare un'occhiata al find
s 'opzione -print0
Il seguente script funziona (almeno per me):
#!/bin/bash
while read I ; do if [ "$I" ] ; then $I ; fi ; done ;