$ ls *mp3 | xargs mplayer
Playing Lemon.
File not found: 'Lemon'
Playing Tree.mp3.
File not found: 'Tree.mp3'
Exiting... (End of file)
ファイル "Lemon Tree.mp3"にスペースが含まれているため、私のコマンドは失敗します。したがって、xargsは2つのファイルであると見なします。このようなファイル名でfind + xargsを機能させることはできますか?
xargs
コマンドは、区切り文字として空白文字(タブ、スペース、改行)を使用します。次のような-d
オプションを使用して、改行文字( '\ n')のみを絞り込むことができます。
ls *.mp3 | xargs -d '\n' mplayer
GNU xargsでのみ機能します。 BSDシステムの場合、次のように-0
オプションを使用します。
ls *.mp3 | xargs -0 mplayer
このメソッドはより単純で、GNU xargsでも機能します。
Xargsユーティリティは、スペース、タブ、改行、およびファイルの終わりで区切られた文字列を標準入力から読み取り、文字列を引数としてユーティリティを実行します。
スペースを区切り文字として使用しないでください。これは、xargsの区切り文字を変更することで実行できます。マニュアルによると:
-0 Change xargs to expect NUL (``\0'') characters as separators, instead of spaces and newlines. This is expected to be used in concert with the -print0 function in find(1).
といった:
find . -name "*.mp3" -print0 | xargs -0 mplayer
7番目のmp3の再生に関する質問に答えるため。実行する方が簡単です
mplayer "$(ls *.mp3 | sed -n 7p)"
試して
find . -name \*.mp3 -print0 | xargs -0 mplayer
の代わりに
ls | grep mp3
macOSのxargsには-dオプションがないため、このソリューションでは代わりに-0を使用します。
Lsを取得して1行に1つのファイルを出力し、改行をヌルに変換し、デリミタとしてヌルを使用するようにxargsに指示します。
ls -1 *mp3 | tr "\n" "\0" | xargs -0 mplayer
Dick.Guertinの回答[1]は、ファイル名のスペースをエスケープできることが、ここで提案されている他の解決策(空白文字ではなくヌル文字をセパレーターとして使用するなど)に代わる価値があることを示唆しました。しかし、それはもっと簡単かもしれません-あなたは本当にユニークなキャラクターを必要としません。エスケープされたスペースを直接sedに追加することができます:
ls | grep ' ' | sed 's| |\\ |g' | xargs ...
さらに、grepが必要なのは、名前にスペースを含むファイルが必要な場合onlyのみです。より一般的には(たとえば、一部にはスペースがあり、一部にはスペースがないファイルのバッチを処理する場合)、grepをスキップします。
ls | sed 's| |\\ |g' | xargs ...
そして、もちろん、ファイル名には空白以外の空白が含まれる場合があります(タブなど):
ls | sed -r 's|[[:blank:]]|\\\1|g' | xargs ...
これは、GNU sedなどの-r(拡張正規表現)またはbsd sedの最新バージョン(たとえば、FreeBSD 8の前に最初にオプション "-E"を綴り、両方をサポートするFreeBSDをサポートする少なくともFreeBSD 11を介した互換性のためのr&-E)。それ以外の場合は、基本的な正規表現文字クラスブラケット式を使用して、スペースとタブ文字を[]
区切り文字に手動で入力できます。
[1]これはおそらく、その回答に対するコメントまたは編集としてより適切ですが、現時点ではコメントするのに十分な評判がなく、編集のみを提案できます。上記の後者の形式(grepなし)はDick.Guertinの元の回答の動作を変更するため、直接編集はおそらく適切ではありません。
find . -name 'Lemon*.mp3' -print0 | xargs -0 -i mplayer '{}'
これは、私の場合、スペースを含む異なるファイルを削除するのに役立ちました。 mplayerでも動作するはずです。必要なトリックは引用符です。 (Linuxでテスト済み Xubunt 14.04)
ls | grep mp3 | sed -n "7p" | xargs -i mplayer {}
上記のコマンドでは、xargs
が各ファイルに対してmplayer
を新たに呼び出すことに注意してください。これはmplayer
には望ましくないかもしれませんが、他のターゲットには問題ないかもしれません。
それは、(a)たとえばレモンとは対照的に、番号7にどのように結び付いているか、および(b)ファイル名のいずれかに改行が含まれているかどうか(および、改行がある場合は名前を変更するかどうか)に依存します。
それに対処する方法はたくさんありますが、そのうちのいくつかは次のとおりです。
mplayer Lemon*.mp3
find . -name 'Lemon*.mp3' -exec mplayer {} ';'
i=0
for mp3 in *.mp3
do
i=$((i+1))
[ $i = 7 ] && mplayer "$mp3"
done
for mp3 in *.mp3
do
case "$mp3" in
(Lemon*) mplayer "$mp3";;
esac
done
i=0
find . -name *.mp3 |
while read mp3
do
i=$((i+1))
[ $i = 7 ] && mplayer "$mp3"
done
ファイル名に改行が含まれている場合、read
ループは機能しません。他の名前は、名前に改行(スペースは言うまでもなく)があっても正しく機能します。私のお金のために、改行を含むファイル名がある場合は、改行なしでファイルの名前を変更する必要があります。ファイル名を二重引用符で囲むことは、ループが正しく機能するための鍵です。
GNU find
およびGNU xargs
(またはFreeBSD(* BSD?)、またはMac OS X)がある場合は、次のように-print0
および-0
オプションを使用することもできます。
find . -name 'Lemon*.mp3' -print0 | xargs -0 mplayer
これは、名前の内容に関係なく機能します(ファイル名に表示できない2文字のみがスラッシュとNULであり、スラッシュはファイルパスに問題を引き起こさないため、名前区切り文字としてNULを使用するとすべてがカバーされます)。ただし、最初の6つのエントリを除外する必要がある場合は、改行ではなくNULで終了する「行」を処理するプログラムが必要です。
1つ目は、手持ちの特定のケースでは断然最もシンプルです。ただし、まだリストされていない他のシナリオをカバーするために一般化されない場合があります。
MacOS 10.12.x(Sierra)では、ファイル名またはサブディレクトリにスペースがある場合、次を使用できます。
find . -name '*.Swift' -exec echo '"{}"' \; |xargs wc -l
xargs
の質問に直接答えていないことは知っていますしかし、find
の-exec
オプションに言及する価値はあります。
次のファイルシステムがあるとします。
[root@localhost bokeh]# tree --charset assci bands
bands
|-- Dream\ Theater
|-- King's\ X
|-- Megadeth
`-- Rush
0 directories, 4 files
Findコマンドを使用して、Dream TheaterとKing's Xのスペースを処理できます。したがって、grepを使用して各バンドのドラマーを検索します。
[root@localhost]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren
-exec
オプションでは、{}
はパスを含むファイル名を表します。エスケープしたり、引用符で囲んだりする必要はありません。
-exec
のターミネータ(+
と\;
)の違いは、+
が1つのコマンドラインにできる限り多くのファイル名をグループ化することです。一方、\;
は各ファイル名に対してコマンドを実行します。
したがって、find bands/ -type f -exec grep Drums {} +
は次のようになります。
grep Drums "bands/Dream Theater" "bands/Rush" "bands/King's X" "bands/Megadeth"
find bands/ -type f -exec grep Drums {} \;
は次の結果になります。
grep Drums "bands/Dream Theater"
grep Drums "bands/Rush"
grep Drums "bands/King's X"
grep Drums "bands/Megadeth"
grep
の場合、これにはファイル名を出力するかしないかの副作用があります。
[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} \;
Drums:Mike Mangini
Drums: Neil Peart
Drums:Jerry Gaskill
Drums:Dirk Verbeuren
[root@localhost bokeh]# find bands/ -type f -exec grep Drums {} +
bands/Dream Theater:Drums:Mike Mangini
bands/Rush:Drums: Neil Peart
bands/King's X:Drums:Jerry Gaskill
bands/Megadeth:Drums:Dirk Verbeuren
もちろん、grep
のオプション-h
および-H
は、grep
の呼び出し方法に関係なく、ファイル名を出力するかどうかを制御します。
xargs
xargs
は、コマンドラインでのmanファイルの方法も制御できます。
xargs
はデフォルトですべての引数を1行にグループ化します。 -exec \;
がxargs -l
を使用するのと同じことを行うために。 -t
オプションは、xargs
にコマンドを実行する前に出力するように指示することに注意してください。
[root@localhost bokeh]# find ./bands -type f | xargs -d '\n' -l -t grep Drums
grep Drums ./bands/Dream Theater
Drums:Mike Mangini
grep Drums ./bands/Rush
Drums: Neil Peart
grep Drums ./bands/King's X
Drums:Jerry Gaskill
grep Drums ./bands/Megadeth
Drums:Dirk Verbeuren
-l
オプションは、xargsにすべてのファイル名に対してgrepを実行するよう指示することを確認してください。
デフォルトと比較(つまり、-l
オプションなし):
[root@localhost bokeh]# find ./bands -type f | xargs -d '\n' -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush ./bands/King's X ./bands/Megadeth
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren
xargs
は、コマンドラインで使用できるファイルの数をより適切に制御します。 -l
オプションにコマンドごとの最大ファイル数を指定します。
[root@localhost bokeh]# find ./bands -type f | xargs -d '\n' -l2 -t grep Drums
grep Drums ./bands/Dream Theater ./bands/Rush
./bands/Dream Theater:Drums:Mike Mangini
./bands/Rush:Drums: Neil Peart
grep Drums ./bands/King's X ./bands/Megadeth
./bands/King's X:Drums:Jerry Gaskill
./bands/Megadeth:Drums:Dirk Verbeuren
[root@localhost bokeh]#
-l2
が原因で、grep
が2つのファイル名で実行されたことを確認してください。
この投稿の具体的なタイトルを考えると、ここに私の提案があります:
ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g'
アイデアは、ブランクを '<'などの任意の固有の文字に変換し、それをバックスラッシュの後にブランクが続く '\'に変更することです。その後、次のような任意のコマンドにパイプすることができます。
ls | grep ' ' | tr ' ' '<' | sed 's|<|\\ |g' | xargs -L1 GetFileInfo
ここで重要なのは、「tr」コマンドと「sed」コマンドです。また、「?」など、「<」以外の任意の文字を使用できますまたはタブ文字も。
代替ソリューションが役立つ場合があります...
Perlを使用して行の末尾にヌル文字を追加してから、xargsで-0
オプションを使用することもできます。 xargs -d '\ n'(承認済みの回答)とは異なり、これはOS Xを含むすべての場所で機能します。
たとえば、スペースやその他の面白い文字が含まれている可能性のあるJPEG画像を再帰的に一覧表示(実行、移動など)するには、次のようにします。
find . | grep \.jpg | Perl -ne 'chop; print "$_\0"' | xargs -0 ls
(注:フィルター処理では、覚えやすい「| grep」構文を「find's」--name引数よりも優先します。)