web-dev-qa-db-ja.com

BASH:文字列から改行文字を削除します(行の読み取り)

私は次の問題にぶつかりました:私は次のことを行うLinuxbashスクリプトを書いています:

  • ファイルから行を読み取る
  • 読んだばかりの行の終わりから\n文字を削除します
  • そこにあるコマンドを実行します

例:commands.txt

ls
ls -l
ls -ltra
ps as

Bashファイルを実行すると、最初の行が取得されて実行されますが、\nが存在する間、シェルは「command not found:ls」を出力するだけです。スクリプトのその部分は次のようになります。

 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

SOに尋ねる前に私が試したことがあるとコメントしました。解決策はありますか?私はこれで最後の数時間脳を壊しています...

11

改行をトリミングするために、私は常にPerl -ne 'chomp and print'が好きです。素晴らしく、覚えやすい。

例えばls -l | Perl -ne 'chomp and print'

ただし

それがここでのあなたの問題ではないと思います。ファイル内のコマンドをシェルスクリプトの「読み取り」に渡す方法がわかりませんが。

このような私自身のテストスクリプト(test.sh)

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

そしてこのようなサンプル入力ファイル(test.cmds)

ls 
ls -l
ls -ltra

この./test.sh < test.cmdsのように実行すると、期待される結果が表示されます。これは、現在の作業ディレクトリで最初のコマンド「ls」を実行することです。

おそらく、入力ファイルに追加の印刷不可能な文字が含まれていますか?

私のはこのように見えます

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

以下のコメントから、入力ファイルにキャリッジリターン( "\ r")が含まれている可能性があります。これは改行と同じではありません。入力ファイルは元々DOS形式ですか?その場合、期待される結果を得るには、「\ r\n」で終わる2バイトのDOS行を1バイトのUNIX行「\ n」に変換する必要があります。

コメントアウトされた行のいずれかで「\ n」を「\ r」に交換することで、これを実行できるはずです。

18
cms

誰かがすでにシェルコマンドを実行するプログラムを書いています:shファイル

本当にファイルの最初の行だけを実行したい場合:head -n 1 file |sh

問題がキャリッジリターンの場合:tr -d '\r' <file |sh

13
Mark Edgar

私はこれを試しました:

read line
echo -n $line | od -x

入力「xxxx」の場合、次のようになります。

0000000 7878 7878

ご覧のとおり、変数の内容の最後に\nはありません。オプション-xbash -x script)を指定してスクリプトを実行することをお勧めします。これにより、実行時にすべてのコマンドが出力されます。

[編集]あなたの問題は、Windowsでcommands.txtを編集したことです。現在、ファイルには、readを混乱させる行区切り文字としてCRLF(0d0a)が含まれています(また、ls\rは既知のコマンドではありません)。 dos2unixなどを使用して、Unixファイルに変換します。

2
Aaron Digulla

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' 
2
jonny

evalコマンドが必要です


#!/bin/bash -x

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

私はそれを実行しました
./ script.sh <file.txt

そしてfile.txtは:

 ls 
 ls -l 
 ls -ltra 
 ps as 
1
sud03r

lsでは機能しませんが、 find-print0オプションを確認することをお勧めします

0
knittl

次のスクリプトは機能します(少なくとも私にとっては):

#!/bin/bash

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