名前にスペースを含む生成されたファイルのリストを編集する方法

名前にスペースを含む生成されたファイルのリストを編集する方法

に基づくファイルから派生した比較的小さいファイル名のリストがありますfind。ファイル名にはスペースや句読点を含めることができますが、印刷できない文字や改行文字は確実に含まれていません。

例えば、

Netherlands/Purge (GDPR) 2020-01-09.txt
Netherlands/Purge (GDPR) 2020-01-27.txt
Switzerland/New mailing 2020-01-27.txt

部分的にファイル間を簡単に前後に移動できるように、このファイルをグループ(vi file1 file2 file3代わりに)で編集したいと思います。vi file1; vi file2; vi file3

私はすでに始まっています生成されたファイル名のリストを引数リストとして使用 - スペースを含める 、標準的なfind -print0 | xargs -0 mycommand解決策があります。残念ながら、mycommand編集者が編集者の場合は機能しません。なぜなら、xargs編集するファイルセットを集めることは可能ですが、標準入力すでにパイプラインからインポートされているため、エディタを所定の場所で実行する方法はありません。パイプ自体find -exec vi {} +だけでなく、ファイル名のセットを検証するためにパイプを使用しているため、これはできませんfind

他のオプションは、コピーして貼り付け、ファイル名のリストを結合し、引用符で囲んでから結果を前に追加することですvi。これら3つのファイルの場合、これは単純ですが、通常は簡単に再利用できるソリューションではありません。

vi 'Netherlands/Purge (GDPR) 2020-01-09.txt' 'Netherlands/Purge (GDPR) 2020-01-27.txt' 'Switzerland/New mailing 2020-01-27.txt'

私が好むシェルとしてGNU / Linuxプラットフォームがある場合bash(重要であれば)、生成されたファイルのリストのようなものをどのように編集できますか?

答え1

Bashにいるから

#!/bin/bash
readarray -d '' -t files < <(find path -type f -print0)
vi -- "${files[@]}"

find path -type f -print0実際のパイプと交換してください。

ファイルに改行文字がない場合でも、ユーザーはこれらのファイル名のサポートを追加しました。グレンジャックマン

bufferの代わりにタブを使用するには、次のフラグをvi追加します。-pvi -p ...


配管が不要な場合は、このオプションを直接使用できます-exec

find path -type f -exec vi -- {} +

答え2

残念ながら、mycommandがエディタの場合は機能しません。なぜなら、xargsは編集するファイルセットを組み合わせることができますが、stdinはすでにパイプからインポートしてエディタを所定の場所で実行する方法を見ることができないからです。

このアプローチはGNU Findutilsのマニュアルページに文書化されていますxargs

   -o, --open-tty
          Reopen stdin as /dev/tty in the child process  before  executing
          the  command.  This is useful if you want xargs to run an inter‐
          active application.

この方法で使用できます

find . -name 'pattern' -print0 | xargs -0o vim

しかし、これは新機能です。 xargs 4.4.2を持つ古いシステムでは表示されません。 xargs 4.7.0を搭載したUbuntu 18では表示されます。

今は10年前と同じオプションがxargsないかもしれませんが、-oBashプロセスの置き換えは10年前に存在し、標準入力ではなくファイルから読み取るオプションがxargsありました。-a

したがって、この問題は解決される可能性があります。次のようにする必要はありませんxargs -o

xargs -0 -a <(find . -name 'pattern' -print0) vim

xargs引数で受け取ったファイルを読み込んでいるので(思うように)標準入力を保持します。

答え3

私が得たコメントでは、以下はあなたの命令です。

find -type f -mtime +14 -mtime -22 -iname '*.xml' | while IFS= read -f x; do xmlstarlet sel -T -t -v '//magicElement' -n "$x" | grep -q magicValue && echo "$x"; done 

while-exec sh -c '...'-loopにパイプするのではなく、パイプを使用してファイルをフィルタリングできます。

find -type f -mtime +14 -mtime -22 -iname '*.xml' \
  -exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
  -exec vi -- {} +

努力する:

3つのファイルを考えてみましょう。

.
├── a:<magicElement>magicValue</magicElement>
├── b:<magicElement>magicValue</magicElement>
└── c:<magicElement>someOtherValue</magicElement>

$ find . -type f \
  -exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
  -exec echo vi -- {} +

出力:

vi -- ./a ./b

答え4

私が長年にわたってこの問題を解決するために使用してきた2つの醜い方法は次のとおりです。どちらもXが必要です。

find ... -print0| ...| xargs -0r gvim -f

find ... -print0| ...| xargs -0r xterm -e vim

SSH経由でも動作します。

関連情報