たとえば、現在、次を使用して、Unix パスをファイルに書き込んだいくつかのファイルを変更しています。
cat file.txt | while read in; do chmod 755 "$in"; done
よりエレガントで安全な方法はありますか?
答えは1つじゃないから…
shell
コマンドライン展開xargs
専用ツールwhile read
いくつかのコメント付きwhile read -u
対話型fd
処理用の専用の使用(サンプル)OP リクエストに関して: fileにリストされているすべてのターゲットで実行chmod
xargs
されているのは、指定されたツールです。ただし、他のアプリケーション、少量のファイルなどの場合...
If your file is not too big and all files are *well named* (without spaces or other special chars like quotes), you could use *`shell` command line expansion*. Simply:
chmod 755 $(<file.txt)
For small amount of files (lines), this command is the lighter one.
xargs
適切なツールですFor bigger amount of files, or almost ***any*** number of lines in your input file...
For many *binutils* tools, like `chown`, `chmod`, `rm`, `cp -t` ...
xargs chmod 755 <file.txt
If you have special chars and/or a lot of lines in `file.txt`.
xargs -0 chmod 755 < <(tr \\n \\0 <file.txt)
if your command need to be run exactly 1 time by entry:
xargs -0 -n 1 chmod 755 < <(tr \\n \\0 <file.txt)
This is not needed for this sample, as `chmod` accept multiple files as argument, but this match the title of question.
For some special case, you could even define location of file argument in commands generateds by `xargs`:
xargs -0 -I '{}' -n 1 myWrapper -arg1 -file='{}' wrapCmd < <(tr \\n \\0 <file.txt)
seq 1 5
入力としてテストするこれを試して:
xargs -n 1 -I{} echo Blah {} blabla {}.. < <(seq 1 5)
Blah 1 blabla 1..
Blah 2 blabla 2..
Blah 3 blabla 3..
Blah 4 blabla 4..
Blah 5 blabla 5..
commande は1 行に 1 回実行されます。
while read
およびバリアント。OPが示唆cat file.txt | while read in; do chmod 755 "$in"; done
するように機能しますが、2つの問題があります:
- `cat |` is an *useless fork*, and
- `| while ... ;done` will become a *subshell* where environment will disapear after `;done`.
したがって、これはより適切に記述できます。
while read in; do chmod 755 "$in"; done < file.txt
しかし、
次の警告$IFS
およびread
フラグが表示される場合があります。
help read
> read: read [-r] ... [-d delim] ... [name ...]
... Reads a single line from the standard input... The line is split into fields as with word splitting, and the first word is assigned to the first NAME, the second word to the second NAME, and so on... Only the characters found in $IFS are recognized as word delimiters. ... Options: ... -d delim continue until the first character of DELIM is read, rather than newline ... -r do not allow backslashes to escape any characters ... Exit Status: The return code is zero, unless end-of-file is encountered...
In some case, you may need to use
while IFS= read -r in;do chmod 755 "$in";done <file.txt
For avoiding problems with stranges filenames. And maybe if you encouter problems with *`UTF-8`*:
while LANG=C IFS= read -r in ; do chmod 755 "$in";done <file.txt
STDIN
読み取りに使用している間file.txt
、スクリプトをインタラクティブにできませんでした (もう使用できませSTDIN
ん)。while read -u
、専用を使用fd
。構文:while read ...;done <file.txt
にリダイレクトSTDIN
しfile.txt
ます。つまり、プロセスが完了するまで、プロセスに対処することはできません。
対話型ツールを作成する予定がある場合はSTDIN
、使用を避け、別のファイル記述子を使用する必要があります。
定数ファイル記述子は0
、STDIN1
用、STDOUT用2
、およびSTDERR用です。あなたはそれらを見ることができます:
ls -l /dev/fd/
また
ls -l /proc/self/fd/
そこから、ファイル記述子0
としてと(実際には、スーパーユーザー ツール63
によってはそれ以上)の間の未使用の番号を選択する必要があります。sysctl
このデモでは、fd 7
を使用します。
exec 7<file.txt # Without spaces between `7` and `<`!
ls -l /dev/fd/
read -u 7
次に、この方法を使用できます。
while read -u 7 filename; do
ans=
while [ -z "$ans" ]; do
read -p "Process file '$filename' (y/n)? " -sn1 foo
[ "$foo" ] && [ -z "${foo/[yn]}" ] && ans=$foo || echo '??'
done
if [ "$ans" = "y" ]; then
echo Yes
echo "Processing '$filename'."
else
echo No
fi
done 7<file.txt
done
閉じるにはfd/7
:
exec 7<&- # This will close file descriptor 7.
ls -l /dev/fd/
注:この構文は、並列プロセスで多くの I/O を実行する場合に役立つ可能性があるため、ストライクバージョンを使用します。
mkfifo sshfifo
exec 7> >(ssh -t user@host sh >sshfifo)
exec 6<sshfifo
はい。
while read in; do chmod 755 "$in"; done < file.txt
これにより、プロセスを回避できcat
ます。
cat
ほとんどの場合、このような目的には適していません。猫の無用な使用について詳しく読むことができます。
素敵なセレクター (たとえば、ディレクトリ内のすべての .txt ファイル) がある場合は、次のことができます。
for i in *.txt; do chmod 755 "$i"; done
またはあなたの変種:
while read line; do chmod 755 "$line"; done < file.txt
コマンドを各行で並行して実行したい場合は、GNU Parallelを使用できます。
parallel -a <your file> <program>
ファイルの各行は引数として program に渡されます。デフォルトでparallel
は、CPU の数と同じ数のスレッドが実行されます。しかし、あなたはそれを指定することができます-j
入力に空白がないことがわかっている場合:
xargs chmod 755 < file.txt
パスに空白が含まれている可能性があり、GNU xargs がある場合:
tr '\n' '\0' < file.txt | xargs -0 chmod 755
bash にタグを付けたようですが、Perl もこれを行うのに適した方法です。
perl -p -e '`chmod 755 $_`' file.txt
正規表現を適用して、適切なファイルを取得していることを確認することもできます。たとえば、.txt ファイルのみを処理します。
perl -p -e 'if(/\.txt$/) `chmod 755 $_`' file.txt
何が起こっているかを「プレビュー」するには、バッククォートを二重引用符に置き換え、先頭に を追加しますprint
。
perl -p -e 'if(/\.txt$/) print "chmod 755 $_"' file.txt