benry-unixcommand 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGES.md +20 -0
- data/MIT-LICENSE +21 -0
- data/README.md +1063 -0
- data/benry-unixcommand.gemspec +31 -0
- data/doc/benry-unixcommand.html +932 -0
- data/doc/css/style.css +168 -0
- data/lib/benry/unixcommand.rb +1322 -0
- data/test/run_all.rb +14 -0
- data/test/unixcommand_test.rb +2517 -0
- metadata +69 -0
data/README.md
ADDED
@@ -0,0 +1,1063 @@
|
|
1
|
+
# Benry-UnixCommand
|
2
|
+
|
3
|
+
($Release: 1.0.0 $)
|
4
|
+
|
5
|
+
|
6
|
+
## What's this?
|
7
|
+
|
8
|
+
Benry-UnixCommand implements popular UNIX commands, like FileUtils,
|
9
|
+
but much better than it.
|
10
|
+
|
11
|
+
* Document: <https://kwatch.github.io/benry-ruby/benry-unixcommand.html>
|
12
|
+
* GitHub: <https://github.com/kwatch/benry-ruby/tree/main/benry-unixcommand>
|
13
|
+
* Changes: <https://github.com/kwatch/benry-ruby/blob/main/benry-unixcommand/CHANGES.md>
|
14
|
+
|
15
|
+
Features compared to FileUtils:
|
16
|
+
|
17
|
+
* supports file patterns (`*`, `.`, `{}`) directly.
|
18
|
+
* provides `cp :r`, `mv :p`, `rm :rf`, ... instead of `cp_r`, `mv_p`, `rm_rf`, ...
|
19
|
+
* prints command prompt `$ ` before command echoback.
|
20
|
+
* provides `pushd` which is similar to `cd` but supports nested calls naturally.
|
21
|
+
* implements `capture2`, `capture2e`, and `capture3` which calls
|
22
|
+
`Popen3.capture2`, `Popen3.capture2`, and `Popen3.capture3` respectively.
|
23
|
+
* supports `touch -r reffile`.
|
24
|
+
* provides `sys` command which is similar to `sh` in Rake but different in details.
|
25
|
+
* provides `zip` and `unzip` commands (requires `rubyzip` gem).
|
26
|
+
* provides `store` command which copies files recursively into target directory, keeping file path.
|
27
|
+
* provides `atomic_symlink!` command which switches symlink atomically.
|
28
|
+
|
29
|
+
(Benry-UnixCommand requires Ruby >= 2.3)
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
### Table of Contents
|
34
|
+
|
35
|
+
<!-- TOC -->
|
36
|
+
|
37
|
+
* [What's this?](#whats-this)
|
38
|
+
* [Install](#install)
|
39
|
+
* [Command Reference](#command-reference)
|
40
|
+
* [`echo`](#echo)
|
41
|
+
* [`echoback`](#echoback)
|
42
|
+
* [`cp`](#cp)
|
43
|
+
* [`mv`](#mv)
|
44
|
+
* [`rm`](#rm)
|
45
|
+
* [`mkdir`](#mkdir)
|
46
|
+
* [`rmdir`](#rmdir)
|
47
|
+
* [`ln`](#ln)
|
48
|
+
* [`atomic_symlink!`](#atomic_symlink)
|
49
|
+
* [`touch`](#touch)
|
50
|
+
* [`chmod`](#chmod)
|
51
|
+
* [`chown`](#chown)
|
52
|
+
* [`pwd`](#pwd)
|
53
|
+
* [`cd`](#cd)
|
54
|
+
* [`pushd`](#pushd)
|
55
|
+
* [`store`](#store)
|
56
|
+
* [`sys`](#sys)
|
57
|
+
* [`ruby`](#ruby)
|
58
|
+
* [`capture2`](#capture2)
|
59
|
+
* [`capture2e`](#capture2e)
|
60
|
+
* [`capture3`](#capture3)
|
61
|
+
* [`zip`](#zip)
|
62
|
+
* [`unzip`](#unzip)
|
63
|
+
* [`time`](#time)
|
64
|
+
* [FAQ](#faq)
|
65
|
+
* [Why `mv` or `cp` requires `to:` option?](#why-mv-or-cp-requires-to-option)
|
66
|
+
* [How to use in Rakefile?](#how-to-use-in-rakefile)
|
67
|
+
* [How to change prompt string?](#how-to-change-prompt-string)
|
68
|
+
* [How to make prompt colored?](#how-to-make-prompt-colored)
|
69
|
+
* [How to disable command echoback?](#how-to-disable-command-echoback)
|
70
|
+
* [License and Copyright](#license-and-copyright)
|
71
|
+
|
72
|
+
<!-- /TOC -->
|
73
|
+
|
74
|
+
|
75
|
+
|
76
|
+
## Install
|
77
|
+
|
78
|
+
```
|
79
|
+
$ gem install benry-unixcommand
|
80
|
+
```
|
81
|
+
|
82
|
+
File: ex1.rb
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
require 'benry/unixcommand' # !!!!!
|
86
|
+
include Benry::UnixCommand # !!!!!
|
87
|
+
|
88
|
+
output = capture2 "uname -srmp" # run command and return output
|
89
|
+
p output
|
90
|
+
```
|
91
|
+
|
92
|
+
Result:
|
93
|
+
|
94
|
+
```terminal
|
95
|
+
[localhost]$ ruby ex1.rb
|
96
|
+
$ uname -srmp
|
97
|
+
"Darwin 22.5.0 arm64 arm\n"
|
98
|
+
```
|
99
|
+
|
100
|
+
|
101
|
+
|
102
|
+
## Command Reference
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
### `echo`
|
107
|
+
|
108
|
+
File: ex-echo1.rb
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
require 'benry/unixcommand'
|
112
|
+
include Benry::UnixCommand
|
113
|
+
|
114
|
+
echo "aa", "bb", "cc"
|
115
|
+
|
116
|
+
echo :n, "aa" # not print "\n"
|
117
|
+
echo "bb"
|
118
|
+
```
|
119
|
+
|
120
|
+
Result:
|
121
|
+
|
122
|
+
```terminal
|
123
|
+
[localhost]$ ruby ex_echo1.rb
|
124
|
+
$ echo aa bb cc
|
125
|
+
aa bb cc
|
126
|
+
$ echo -n aa
|
127
|
+
aa$ echo bb
|
128
|
+
bb
|
129
|
+
```
|
130
|
+
|
131
|
+
Options:
|
132
|
+
|
133
|
+
* `echo :n` -- don't print "\n".
|
134
|
+
|
135
|
+
|
136
|
+
|
137
|
+
### `echoback`
|
138
|
+
|
139
|
+
* `echoback "command"` prints `$ command` string into stdout.
|
140
|
+
* `echoback "command"` indents command if in block of `cd` or `pushd`.
|
141
|
+
|
142
|
+
File: ex-echoback1.rb
|
143
|
+
|
144
|
+
```
|
145
|
+
require 'benry/unixcommand'
|
146
|
+
include Benry::UnixCommand
|
147
|
+
|
148
|
+
echoback "command 123"
|
149
|
+
cd "dir1" do
|
150
|
+
echoback "command 456"
|
151
|
+
cd "dir2" do
|
152
|
+
echoback "command 789"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
Result:
|
158
|
+
|
159
|
+
```terminal
|
160
|
+
[localhost]$ ruby ex_echoback1.rb
|
161
|
+
$ command 123
|
162
|
+
$ cd dir1
|
163
|
+
$ command 456
|
164
|
+
$ cd dir2
|
165
|
+
$ command 789
|
166
|
+
$ cd -
|
167
|
+
$ cd -
|
168
|
+
```
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
### `cp`
|
173
|
+
|
174
|
+
* `cp "x", "y"` copies `x` to new file `y'. Fails when `y` already exists.
|
175
|
+
* `cp! "x", "y"` is similar to above, but overwrites `y` even if it exists.
|
176
|
+
* `cp "x", "y", to: "dir"` copies `x` and `y` into `dir`.
|
177
|
+
* `cp "x", "y", "dir"` will be error! (use `to: "dir"` instead.)
|
178
|
+
* Glob pattern such as `*`, `**`, `?`, and `{}` are available.
|
179
|
+
* (See [FAQ](#faq) about `to:` keyword option.)
|
180
|
+
* If you want to copy files with keeping directory structure, use `store` instead of `cp`.
|
181
|
+
|
182
|
+
<!--
|
183
|
+
File: ex-cp1.rb
|
184
|
+
-->
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
require 'benry/unixcommand'
|
188
|
+
include Benry::UnixCommand
|
189
|
+
|
190
|
+
## copy file to newfile
|
191
|
+
cp "file1.txt", "newfile.txt" # error if newfile.txt already exists.
|
192
|
+
cp! "file1.txt", "newfile.txt" # overrides newfile.txt if exists.
|
193
|
+
|
194
|
+
## copy dir to newdir recursively
|
195
|
+
cp :r, "dir1", "newdir" # error if newdir already exists.
|
196
|
+
|
197
|
+
## copy files to existing directory
|
198
|
+
cp :pr, "file*.txt", "lib/**/*.rb", to: "dir1" # error if dir1 not exist.
|
199
|
+
```
|
200
|
+
|
201
|
+
Options:
|
202
|
+
|
203
|
+
* `cp :p` -- preserves timestamps and permission.
|
204
|
+
* `cp :r` -- copies files and directories recursively.
|
205
|
+
* `cp :l` -- creates hard links instead of copying files.
|
206
|
+
* `cp :f` -- ignores non-existing source files.
|
207
|
+
Notice that this is different from `cp -f` of unix command.
|
208
|
+
|
209
|
+
|
210
|
+
|
211
|
+
### `mv`
|
212
|
+
|
213
|
+
* `mv "x", "y"` renames `x` to `y`. Fails when `y` already exists.
|
214
|
+
* `mv! "x", "y"` is similar to above, but overwrites `y` even if it exists.
|
215
|
+
* `mv "x", "y", to: "dir"` moves `x` and `y` into `dir`.
|
216
|
+
* `mv "x", "y", "dir"` will be error! (use `to: "dir"` instead.)
|
217
|
+
* Glob patten such as `*`, `**`, `?`, and `{}` are available.
|
218
|
+
* (See [FAQ](#faq) about `to:` keyword option.)
|
219
|
+
|
220
|
+
<!--
|
221
|
+
File: ex-mv1.rb
|
222
|
+
-->
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
require 'benry/unixcommand'
|
226
|
+
include Benry::UnixCommand
|
227
|
+
|
228
|
+
## rename file
|
229
|
+
mv "file1.txt", "newfile.txt" # error if newfile.txt already exists.
|
230
|
+
mv! "file1.txt", "newfile.txt" # overrides newfile.txt if exists.
|
231
|
+
|
232
|
+
## rename directory
|
233
|
+
mv "dir1", "newdir" # error if newdir already exists.
|
234
|
+
|
235
|
+
## move files and directories to existing directory
|
236
|
+
mv "file*.txt", "lib", to: "dir1" # error if dir1 not exist.
|
237
|
+
|
238
|
+
## ignore non-existing files.
|
239
|
+
mv "foo*.txt", to: "dir1" # error if foo*.txt not exist.
|
240
|
+
mv :f, "foo*.txt", to: "dir1" # not error even if foo*.txt not exist.
|
241
|
+
```
|
242
|
+
|
243
|
+
Options:
|
244
|
+
|
245
|
+
* `mv :f` -- ignores non-existing source files.
|
246
|
+
|
247
|
+
|
248
|
+
|
249
|
+
### `rm`
|
250
|
+
|
251
|
+
* `rm "x", "y"` removes file `x` and `y`.
|
252
|
+
* `rm :r, "dir1"` removes directory recursively.
|
253
|
+
* `rm "dir1"` will raise error because `:r` option not specified.
|
254
|
+
* `rm "foo*.txt"` will raise error if `foo*.txt` not exists.
|
255
|
+
* `rm :f, "foo*.txt"` will not raise error even if `foo*.txt` not exists.
|
256
|
+
* Glob patten such as `*`, `**`, `?`, and `{}` are available.
|
257
|
+
|
258
|
+
<!--
|
259
|
+
File: ex-rm1.rb
|
260
|
+
-->
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
require 'benry/unixcommand'
|
264
|
+
include Benry::UnixCommand
|
265
|
+
|
266
|
+
## remove files
|
267
|
+
rm "foo*.txt", "bar*.txt" # error if files not exist.
|
268
|
+
rm :f, "foo*.txt", "bar*.txt" # not error even if files not exist.
|
269
|
+
|
270
|
+
## remove directory
|
271
|
+
rm :r, "dir1" # error if dir1 not exist.
|
272
|
+
rm :rf, "dir1" # not error even if dir1 not exist.
|
273
|
+
```
|
274
|
+
|
275
|
+
Options:
|
276
|
+
|
277
|
+
* `rm :r` -- remove files and directories recursively.
|
278
|
+
* `rm :f` -- ignores non-existing files and directories.
|
279
|
+
|
280
|
+
|
281
|
+
|
282
|
+
### `mkdir`
|
283
|
+
|
284
|
+
* `mkdir "x", "y"` creates `x` and `y` directories.
|
285
|
+
* `mkdir :p, "x/y/z"` creates `x/y/z` directory.
|
286
|
+
* `mkdir "x"` will be error if `x` already exists.
|
287
|
+
* `mkdir :p, "x"` will not be error even if `x` already exists.
|
288
|
+
* `mkdir :m, 0775, "x"` creates new directory with permission 0775.
|
289
|
+
|
290
|
+
<!--
|
291
|
+
File: ex-mkdir1.rb
|
292
|
+
-->
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
require 'benry/unixcommand'
|
296
|
+
include Benry::UnixCommand
|
297
|
+
|
298
|
+
## creates new directory
|
299
|
+
mkdir "newdir"
|
300
|
+
|
301
|
+
## creates new directory with path
|
302
|
+
mkdir :p, "dir/x/y/z"
|
303
|
+
|
304
|
+
## creats new directory with specific permission
|
305
|
+
mkdir :m, 0755, "newdir"
|
306
|
+
```
|
307
|
+
|
308
|
+
Options:
|
309
|
+
|
310
|
+
* `mkdir :p` -- creates intermediate path.
|
311
|
+
* `mkdir :m, 0XXX` -- specifies directory permission.
|
312
|
+
|
313
|
+
|
314
|
+
|
315
|
+
### `rmdir`
|
316
|
+
|
317
|
+
* `rmdir "x", "y"` removed empty directores.
|
318
|
+
* Raises error when directory not empty.
|
319
|
+
|
320
|
+
<!--
|
321
|
+
File: ex-rmdir1.rb
|
322
|
+
-->
|
323
|
+
|
324
|
+
```ruby
|
325
|
+
require 'benry/unixcommand'
|
326
|
+
include Benry::UnixCommand
|
327
|
+
|
328
|
+
## remove empty directory
|
329
|
+
rmdir "dir" # error if directory not empty.
|
330
|
+
```
|
331
|
+
|
332
|
+
Options:
|
333
|
+
|
334
|
+
* (no options)
|
335
|
+
|
336
|
+
|
337
|
+
|
338
|
+
### `ln`
|
339
|
+
|
340
|
+
* `ln "x", "y"` creates hard link.
|
341
|
+
* `ln :s, "x", "y"` creates symbolic link. Error if `y` already exists.
|
342
|
+
* `ln! :s, "x", "y"` overwrites existing symbolic link `y`.
|
343
|
+
* `ln "files*.txt', to: "dir"` creates hard links into `dir`.
|
344
|
+
* `ln "files*.txt', "dir"` will be error! (use `to: "dir"` instead.)
|
345
|
+
* (See [FAQ](#faq) about `to:` keyword option.)
|
346
|
+
|
347
|
+
<!--
|
348
|
+
File: ex-ln1.rb
|
349
|
+
-->
|
350
|
+
|
351
|
+
```ruby
|
352
|
+
require 'benry/unixcommand'
|
353
|
+
include Benry::UnixCommand
|
354
|
+
|
355
|
+
## create hard link
|
356
|
+
ln "foo1.txt", "dir/foo1.txt"
|
357
|
+
|
358
|
+
## create symbolic link
|
359
|
+
ln :s, "foo1.txt", "dir/foo1.txt" # error if dir/foo1.txt alreay exists.
|
360
|
+
ln! :s, "foo1.txt", "dir/foo1.txt" # overwrites dir/foo1.txt if exists.
|
361
|
+
|
362
|
+
## create symbolic link into directory.
|
363
|
+
ln :s, "foo1.txt", to: "dir"
|
364
|
+
|
365
|
+
## error! use ``to: "dir"`` instead.
|
366
|
+
ln :s, "foo1.txt", "dir"
|
367
|
+
```
|
368
|
+
|
369
|
+
|
370
|
+
|
371
|
+
### `atomic_symlink!`
|
372
|
+
|
373
|
+
* `atomic_symlink! "x", "y"` creates symbolic link atomically.
|
374
|
+
|
375
|
+
<!--
|
376
|
+
File: ex-atomic_symlink1.rb
|
377
|
+
-->
|
378
|
+
|
379
|
+
```ruby
|
380
|
+
require 'benry/unixcommand'
|
381
|
+
include Benry::UnixCommand
|
382
|
+
|
383
|
+
## create symbolic link atomically
|
384
|
+
atomic_symlink! "src-20200101", "src"
|
385
|
+
|
386
|
+
## the above is same as the following
|
387
|
+
tmplink = "src.#{rand().to_s[2..6]}" # random name
|
388
|
+
File.symlink("src-20200101", tmplink) # create symblink with random name
|
389
|
+
File.rename(tmplink, "src") # rename symlink atomically
|
390
|
+
```
|
391
|
+
|
392
|
+
Options:
|
393
|
+
|
394
|
+
* (no options)
|
395
|
+
|
396
|
+
|
397
|
+
|
398
|
+
### `touch`
|
399
|
+
|
400
|
+
* `touch "x"` updates timestamp of file.
|
401
|
+
* `touch :r, "reffile", "x"` uses timestamp of `reffile` instead current timestamp.
|
402
|
+
|
403
|
+
<!--
|
404
|
+
File: ex-touch1.rb
|
405
|
+
-->
|
406
|
+
|
407
|
+
```ruby
|
408
|
+
require 'benry/unixcommand'
|
409
|
+
include Benry::UnixCommand
|
410
|
+
|
411
|
+
## updates timestamp of files to current timestamp.
|
412
|
+
touch "files*.txt"
|
413
|
+
|
414
|
+
## copy timestamp from reffile to other files.
|
415
|
+
touch :r, "reffile", "files*.txt"
|
416
|
+
```
|
417
|
+
|
418
|
+
Options:
|
419
|
+
|
420
|
+
* `touch :a` -- updates only access time.
|
421
|
+
* `touch :m` -- updates only modification time.
|
422
|
+
* `touch :r, "reffile"` -- uses timestamp of `reffile` instead of current timestamp.
|
423
|
+
|
424
|
+
|
425
|
+
|
426
|
+
### `chmod`
|
427
|
+
|
428
|
+
* `chmod 0644, "x"` changes file permission.
|
429
|
+
* `chmod :R, "a+r", "dir"` changes permissions recursively.
|
430
|
+
* Permission can be `0644` sytle, or `u+w` style.
|
431
|
+
|
432
|
+
<!--
|
433
|
+
File: ex-chmod1.rb
|
434
|
+
-->
|
435
|
+
|
436
|
+
```ruby
|
437
|
+
require 'benry/unixcommand'
|
438
|
+
include Benry::UnixCommand
|
439
|
+
|
440
|
+
## change permissions of files.
|
441
|
+
chmod 0644, "file*.txt"
|
442
|
+
chmod "a+r", "file*.txt"
|
443
|
+
|
444
|
+
## change permissions recursively.
|
445
|
+
chmod :R, 0644, "dir"
|
446
|
+
chmod :R, "a+r", "dir"
|
447
|
+
```
|
448
|
+
|
449
|
+
Options:
|
450
|
+
|
451
|
+
* `chmod :R` -- changes permissions recursively.
|
452
|
+
|
453
|
+
|
454
|
+
|
455
|
+
### `chown`
|
456
|
+
|
457
|
+
* `chown "user:group", "x", "y"` changes owner and group of files.
|
458
|
+
* `chown "user", "x", "y"` changes owner of files.
|
459
|
+
* `chown ":group", "x", "y"` changes group of files.
|
460
|
+
* `chown :R, "user:group", "dir"` changes owner and group recursively.
|
461
|
+
|
462
|
+
<!--
|
463
|
+
File: ex-chown1.rb
|
464
|
+
-->
|
465
|
+
|
466
|
+
```ruby
|
467
|
+
require 'benry/unixcommand'
|
468
|
+
include Benry::UnixCommand
|
469
|
+
|
470
|
+
## change owner and/or group.
|
471
|
+
chown "user1:group1", "file*.txt" # change both owner and group
|
472
|
+
chown "user1", "file*.txt" # change owner
|
473
|
+
chown ":group1", "file*.txt" # change group
|
474
|
+
```
|
475
|
+
|
476
|
+
Options:
|
477
|
+
|
478
|
+
* `chown :R` -- changes owner and/or group recursively.
|
479
|
+
|
480
|
+
|
481
|
+
|
482
|
+
### `pwd`
|
483
|
+
|
484
|
+
* `pwd()` prints current working directory path.
|
485
|
+
|
486
|
+
<!--
|
487
|
+
File: ex-pwd1.rb
|
488
|
+
-->
|
489
|
+
|
490
|
+
```ruby
|
491
|
+
require 'benry/unixcommand'
|
492
|
+
include Benry::UnixCommand
|
493
|
+
|
494
|
+
## prints current working directory
|
495
|
+
pwd() #=> /home/yourname (for example)
|
496
|
+
```
|
497
|
+
|
498
|
+
Options:
|
499
|
+
|
500
|
+
* (no options)
|
501
|
+
|
502
|
+
|
503
|
+
|
504
|
+
### `cd`
|
505
|
+
|
506
|
+
* `cd` changes current working directory.
|
507
|
+
* If block given, `cd` invokes block just after changing current directory,
|
508
|
+
and back to previous directory automatically.
|
509
|
+
* Within block argument, echoback indentation is increased.
|
510
|
+
* `chdir` is an alias to `cd`.
|
511
|
+
|
512
|
+
File: ex-cd1.rb
|
513
|
+
|
514
|
+
```ruby
|
515
|
+
require 'benry/unixcommand'
|
516
|
+
include Benry::UnixCommand
|
517
|
+
|
518
|
+
## change directory, invoke block, and back to previous directory.
|
519
|
+
pwd() #=> /home/yourname (for example)
|
520
|
+
cd "/tmp" do
|
521
|
+
pwd() #=> /tmp
|
522
|
+
end
|
523
|
+
pwd() #=> /home/yourname (for example)
|
524
|
+
|
525
|
+
## just change directory
|
526
|
+
cd "/tmp"
|
527
|
+
pwd() #=> /tmp
|
528
|
+
```
|
529
|
+
|
530
|
+
Result:
|
531
|
+
|
532
|
+
```terminal
|
533
|
+
[localhost]$ ruby ex-cd1.rb
|
534
|
+
$ pwd
|
535
|
+
/home/yourname
|
536
|
+
$ cd /tmp
|
537
|
+
$ pwd
|
538
|
+
/tmp
|
539
|
+
$ cd -
|
540
|
+
$ pwd
|
541
|
+
/home/yourname
|
542
|
+
$ cd /tmp
|
543
|
+
$ pwd
|
544
|
+
/tmp
|
545
|
+
```
|
546
|
+
|
547
|
+
Options:
|
548
|
+
|
549
|
+
* (no options)
|
550
|
+
|
551
|
+
|
552
|
+
|
553
|
+
### `pushd`
|
554
|
+
|
555
|
+
* `pushd` changes current directory, invokes block, and back to previous directory.
|
556
|
+
* `pushd` requires block argument. `cd` also takes block argument but it is an optional.
|
557
|
+
* Within block argument, echoback indentation is increased.
|
558
|
+
|
559
|
+
File: ex-pushd1.rb
|
560
|
+
|
561
|
+
```ruby
|
562
|
+
require 'benry/unixcommand'
|
563
|
+
include Benry::UnixCommand
|
564
|
+
|
565
|
+
## change directory, invoke block, and back to previous directory.
|
566
|
+
pwd() #=> /home/yourname (for example)
|
567
|
+
pushd "/var" do
|
568
|
+
pwd() #=> /var
|
569
|
+
pushd "tmp" do
|
570
|
+
pwd() #=> /var/tmp
|
571
|
+
end
|
572
|
+
pwd() #=> /var
|
573
|
+
end
|
574
|
+
pwd() #=> /home/yourname (for example)
|
575
|
+
```
|
576
|
+
|
577
|
+
Result:
|
578
|
+
|
579
|
+
```terminal
|
580
|
+
[localhost]$ ruby ex-pushd1.rb
|
581
|
+
$ pwd
|
582
|
+
/home/yourname
|
583
|
+
$ pushd /var
|
584
|
+
$ pwd
|
585
|
+
/var
|
586
|
+
$ pushd tmp
|
587
|
+
$ pwd
|
588
|
+
/var/tmp
|
589
|
+
$ popd # back to /var
|
590
|
+
$ pwd
|
591
|
+
/var
|
592
|
+
$ popd # back to /home/yourname
|
593
|
+
$ pwd
|
594
|
+
/home/yourname
|
595
|
+
```
|
596
|
+
|
597
|
+
Options:
|
598
|
+
|
599
|
+
* (no options)
|
600
|
+
|
601
|
+
|
602
|
+
|
603
|
+
### `store`
|
604
|
+
|
605
|
+
* `store "x", "y", to: "dir", ` copies files under `x` and `y` to `dir` keeping file path.
|
606
|
+
For example, `x/foo/bar.rb` will be copied as `dir/x/foo/bar.rb`.
|
607
|
+
* `store!` overwrites existing files while `store` doesn't.
|
608
|
+
|
609
|
+
<!--
|
610
|
+
File: ex-store1.rb
|
611
|
+
-->
|
612
|
+
|
613
|
+
```ruby
|
614
|
+
require 'benry/unixcommand'
|
615
|
+
include Benry::UnixCommand
|
616
|
+
|
617
|
+
## copies files into builddir, keeping file path
|
618
|
+
store "lib/**/*.rb", "test/**/*.rb", to: "builddir"
|
619
|
+
|
620
|
+
## `store()` is similar to unix `tar` command.
|
621
|
+
## $ tar cf - lib/**/*.rb test/**/*.rb | (cd builddir; tar xf -)
|
622
|
+
```
|
623
|
+
|
624
|
+
Options:
|
625
|
+
|
626
|
+
* `store :p` -- preserves timestamps, permission, file owner and group.
|
627
|
+
* `store :l` -- creates hard link instead of copying file.
|
628
|
+
* `store :f` -- ignores non-existing files.
|
629
|
+
|
630
|
+
|
631
|
+
|
632
|
+
### `sys`
|
633
|
+
|
634
|
+
* `sys "ls -al"` runs `ls -al` command.
|
635
|
+
* `sys` raises error when command failed.
|
636
|
+
* `sys!` ignores error even when command failed.
|
637
|
+
* `sys` and `sys!` return `Process::Status` object regardless of command result.
|
638
|
+
* `sys` and `sys!` can take a block argument as error handler called only when command failed.
|
639
|
+
If result of block argument is truthy, error will not be raised.
|
640
|
+
|
641
|
+
<!--
|
642
|
+
File: ex-sys1.rb
|
643
|
+
-->
|
644
|
+
|
645
|
+
```ruby
|
646
|
+
require 'benry/unixcommand'
|
647
|
+
include Benry::UnixCommand
|
648
|
+
|
649
|
+
## run ``ls`` command
|
650
|
+
sys "ls foo.txt" # may raise error when command failed
|
651
|
+
sys! "ls foo.txt" # ignore error even when command filed
|
652
|
+
|
653
|
+
## error handling
|
654
|
+
sys "ls /fooobarr" do |stat| # block called only when command failed
|
655
|
+
p stats.class #=> Process::Status
|
656
|
+
p stat.exitstatus #=> 1 (non-zero)
|
657
|
+
true # suppress raising error
|
658
|
+
end
|
659
|
+
```
|
660
|
+
|
661
|
+
* `sys "echo *.txt"` (a single string) invokes `echo` command via shell.
|
662
|
+
* `sys "echo", "*.txt"` (multiple strings) invokes `echo` command without shell,
|
663
|
+
and `*.txt` will be globbed by `sys`.
|
664
|
+
* `sys ["echo", "*.txt"]` (an array of strings) invokes `echo` command without shell,
|
665
|
+
and `*.txt` will NOT be globbed by `sys`.
|
666
|
+
If you need to run command without shell nor globbing, `sys ["command ..."]` is the solution.
|
667
|
+
* `sys ["echo"], "*.txt"` raises error.
|
668
|
+
|
669
|
+
<!--
|
670
|
+
File: ex-sys2.rb
|
671
|
+
-->
|
672
|
+
|
673
|
+
```ruby
|
674
|
+
require 'benry/unixcommand'
|
675
|
+
include Benry::UnixCommand
|
676
|
+
|
677
|
+
## Example: assume that there are two files "A.txt" and "B.txt".
|
678
|
+
|
679
|
+
## with shell, with globbing (by shell) ### Output:
|
680
|
+
sys "echo *.txt" # $ echo *.txt
|
681
|
+
# A.txt B.txt
|
682
|
+
|
683
|
+
## no shell, with globbing (by `sys`) ### Output:
|
684
|
+
sys "echo", "*.txt" # $ echo *.txt
|
685
|
+
# A.txt B.txt
|
686
|
+
|
687
|
+
## no shell, no globbing ### Output:
|
688
|
+
sys ["echo", "*.txt"] # $ echo *.txt
|
689
|
+
# *.txt
|
690
|
+
|
691
|
+
## error
|
692
|
+
sys ["echo"], "*.txt" #=> ArgumentError
|
693
|
+
```
|
694
|
+
|
695
|
+
Options:
|
696
|
+
|
697
|
+
* `sys :q` -- quiet mode (suppress echoback of command).
|
698
|
+
|
699
|
+
|
700
|
+
|
701
|
+
### `ruby`
|
702
|
+
|
703
|
+
* `ruby "...."` is almost same as `sys "ruby ...."`.
|
704
|
+
* `RbConfig.ruby` is used as ruby command path.
|
705
|
+
* `ruby` raises error when ruby command failed.
|
706
|
+
* `ruby!` ignores error even when ruby command failed.
|
707
|
+
|
708
|
+
<!--
|
709
|
+
File: ex-ruby1.rb
|
710
|
+
-->
|
711
|
+
|
712
|
+
```ruby
|
713
|
+
require 'benry/unixcommand'
|
714
|
+
include Benry::UnixCommand
|
715
|
+
|
716
|
+
## run ruby command
|
717
|
+
ruby "file1.rb" # raise error when ruby command failed
|
718
|
+
ruby! "file1.rb" # ignore error even when ruby command filed
|
719
|
+
```
|
720
|
+
|
721
|
+
Options:
|
722
|
+
|
723
|
+
* (no options)
|
724
|
+
|
725
|
+
|
726
|
+
|
727
|
+
### `capture2`
|
728
|
+
|
729
|
+
* `capture2 "ls -al"` runs `ls -al` and returns output of the command.
|
730
|
+
* `capture2 "cat -n", stdin_data: "A\nB\n"` run `cat -n` command and uses `"A\nB\n"` as stdin data.
|
731
|
+
* `caputre2 "ls foo"` will raise error when command failed.
|
732
|
+
* `caputre2! "ls foo"` ignores error even when command failed, and returns command output and process status object.
|
733
|
+
* `capture2()` invokes `Popen3.capture2()` internally. All keyword arguments are available.
|
734
|
+
|
735
|
+
<!--
|
736
|
+
File: ex-capture2.rb
|
737
|
+
-->
|
738
|
+
|
739
|
+
```ruby
|
740
|
+
require 'benry/unixcommand'
|
741
|
+
include Benry::UnixCommand
|
742
|
+
|
743
|
+
## run command and get output of the command.
|
744
|
+
output = capture2 "ls -l foo.txt" # error if command failed
|
745
|
+
output, process_status = capture2! "ls -l foot.xt" # ignore error even command failed
|
746
|
+
puts process_status.exitstatus #=> 1
|
747
|
+
|
748
|
+
## run command with stdin data.
|
749
|
+
input = "AA\nBB\nCC\n"
|
750
|
+
output = capture2 "cat -n", stdin_data: input
|
751
|
+
```
|
752
|
+
|
753
|
+
Options:
|
754
|
+
|
755
|
+
* see [`Popen3.capture2()` manual page](https://docs.ruby-lang.org/en/master/Open3.html#method-c-capture2).
|
756
|
+
|
757
|
+
|
758
|
+
|
759
|
+
### `capture2e`
|
760
|
+
|
761
|
+
* almost same as `capture2`, but output contains both stdout and stderr.
|
762
|
+
|
763
|
+
<!--
|
764
|
+
File: ex-capture2e.rb
|
765
|
+
-->
|
766
|
+
|
767
|
+
```ruby
|
768
|
+
require 'benry/unixcommand'
|
769
|
+
include Benry::UnixCommand
|
770
|
+
|
771
|
+
## run command and get output of the command, including stderr.
|
772
|
+
output = capture2e "time ls -al"
|
773
|
+
output, process_status = capture2e! "time ls -al" # ignore error even command failed
|
774
|
+
puts process_status.exitstatus
|
775
|
+
```
|
776
|
+
|
777
|
+
Options:
|
778
|
+
|
779
|
+
* see [`Popen3.capture2e()` manual page](https://docs.ruby-lang.org/en/master/Open3.html#method-c-capture2e).
|
780
|
+
|
781
|
+
|
782
|
+
|
783
|
+
### `capture3`
|
784
|
+
|
785
|
+
* almost same as `capture2`, but returns both stdout output and stderr output.
|
786
|
+
|
787
|
+
<!--
|
788
|
+
File: ex-capture3.rb
|
789
|
+
-->
|
790
|
+
|
791
|
+
```ruby
|
792
|
+
require 'benry/unixcommand'
|
793
|
+
include Benry::UnixCommand
|
794
|
+
|
795
|
+
## run command and get output of both stdout and stderr separately
|
796
|
+
output, error = capture3 "time ls -al"
|
797
|
+
output, error, process_status = capture3! "time ls -al" # ignore error even command failed
|
798
|
+
puts process_status.exitstatus
|
799
|
+
|
800
|
+
## run command with stdin data.
|
801
|
+
input = "AA\nBB\nCC\n"
|
802
|
+
output, error = capture3 "cat -n", stdin_data: input
|
803
|
+
```
|
804
|
+
|
805
|
+
Options:
|
806
|
+
|
807
|
+
* see [`Popen3.capture3()` manual page](https://docs.ruby-lang.org/en/master/Open3.html#method-c-capture3).
|
808
|
+
|
809
|
+
|
810
|
+
|
811
|
+
### `zip`
|
812
|
+
|
813
|
+
* `zip "foo.zip", "file1", "file2"` creates new zip file `foo.zip`.
|
814
|
+
* `zip :r, "foo.zip", "dir1"` adds files under `dir1` into zip file recursively.
|
815
|
+
* `zip` will be error if zip file already exists.
|
816
|
+
* `zip!` will overwrite existing zip file.
|
817
|
+
* `zip :'0'` doesn't compress files.
|
818
|
+
* `zip :'1'` compress files in best speed.
|
819
|
+
* `zip :'9'` compress files in best compression level.
|
820
|
+
* `zip` and `zip!` loads `rubyzip` gem automatically. You must install it by yourself.
|
821
|
+
* (`rubyzip` gem is necessary ONLY when `zip` or `zip!` command is invoked.)
|
822
|
+
* `zip` and `zip!` doesn't support absolute path.
|
823
|
+
|
824
|
+
<!--
|
825
|
+
File: ex-zip1.rb
|
826
|
+
-->
|
827
|
+
|
828
|
+
```ruby
|
829
|
+
require 'benry/unixcommand'
|
830
|
+
include Benry::UnixCommand
|
831
|
+
|
832
|
+
## create zip file
|
833
|
+
zip "foo.zip", "file*.txt" # requires 'rubyzip' gem
|
834
|
+
|
835
|
+
## create zip file, adding files under directory
|
836
|
+
zip :r, "foo.zip", "dir1"
|
837
|
+
|
838
|
+
## create high-compressed zip file
|
839
|
+
zip :r9, "foo.zip", "dir1"
|
840
|
+
```
|
841
|
+
|
842
|
+
Options:
|
843
|
+
|
844
|
+
* `zip :r` -- adds files under directory into zip file recursively.
|
845
|
+
* `zip :'0'` -- not compress files.
|
846
|
+
* `zip :'1'` -- compress files in best speed.
|
847
|
+
* `zip :'9'` -- compress files in best compression level.
|
848
|
+
|
849
|
+
|
850
|
+
|
851
|
+
### `unzip`
|
852
|
+
|
853
|
+
* `unzip "foo.zip"` extracts files in zip file into current directory.
|
854
|
+
* `unzip :d, "dir1", "foo.zip"` extracts files under `dir1`.
|
855
|
+
Diretory `dir1` should not exist or should be empty.
|
856
|
+
* `unzip "foo.zip"` will be error if extracting file already exists.
|
857
|
+
* `unzip! "foo.zip"` will overwrite existing files.
|
858
|
+
* `unzip "foo.txt", "file1", "file2"` extracts only `file1` and `file2`.
|
859
|
+
* `zunip` and `unzip!` loads `rubyzip` gem automatically. You must install it by yourself.
|
860
|
+
* (`rubyzip` gem is necessary ONLY when `unzip` or `unzip!` command is invoked.)
|
861
|
+
* `unzip` and `unzip!` doesn't support absolute path.
|
862
|
+
|
863
|
+
<!--
|
864
|
+
File: ex-unzip1.zip
|
865
|
+
-->
|
866
|
+
|
867
|
+
```ruby
|
868
|
+
require 'benry/unixcommand'
|
869
|
+
include Benry::UnixCommand
|
870
|
+
|
871
|
+
## extracts zip file
|
872
|
+
unzip "foo.zip" # requires 'rubyzip' gem
|
873
|
+
|
874
|
+
## extracts files in zip file into the directory.
|
875
|
+
unzip :d, "dir1", "foo.zip" # 'dir1' should be empty, or should not exist
|
876
|
+
|
877
|
+
## overwrites existing files.
|
878
|
+
unzip! "foo.zip"
|
879
|
+
```
|
880
|
+
|
881
|
+
Options:
|
882
|
+
|
883
|
+
* `unzip :d, "dir1"` -- extracts files into the directory.
|
884
|
+
|
885
|
+
|
886
|
+
|
887
|
+
### `time`
|
888
|
+
|
889
|
+
* `time do ... end` invokes block and prints elapsed time into stderr.
|
890
|
+
|
891
|
+
File: ex-time1.rb
|
892
|
+
|
893
|
+
```ruby
|
894
|
+
require 'benry/unixcommand'
|
895
|
+
include Benry::UnixCommand
|
896
|
+
|
897
|
+
time do
|
898
|
+
sys "zip -qr9 dir1.zip dir1"
|
899
|
+
end
|
900
|
+
```
|
901
|
+
|
902
|
+
Result:
|
903
|
+
|
904
|
+
```termianl
|
905
|
+
[localhost]$ ruby ex-time1.rb
|
906
|
+
$ zip -qr9 dir1.zip dir1
|
907
|
+
|
908
|
+
1.511s real 1.501s user 0.006s sys
|
909
|
+
```
|
910
|
+
|
911
|
+
|
912
|
+
|
913
|
+
## FAQ
|
914
|
+
|
915
|
+
|
916
|
+
|
917
|
+
### Why `mv` or `cp` requires `to:` option?
|
918
|
+
|
919
|
+
Because UNIX command has bad interface which causes unexpected result.
|
920
|
+
|
921
|
+
For example, `mv` command of UNIX has two function: **rename** and **move**.
|
922
|
+
|
923
|
+
* rename: `mv foo bar` (if `bar` is a file or not exist)
|
924
|
+
* move: `mv foo bar` (if directory `bar` already exists)
|
925
|
+
|
926
|
+
Obviously, rename function and move function are same form.
|
927
|
+
This causes unexpected result easily due to, for example, typo.
|
928
|
+
|
929
|
+
```terminal
|
930
|
+
### Assume that you want rename 'foo' file to 'bar'.
|
931
|
+
### But if 'bar' exists as directory, mv command moves 'foo' into 'bar'.
|
932
|
+
### In this case, mv command should be error.
|
933
|
+
$ mv foo bar
|
934
|
+
```
|
935
|
+
|
936
|
+
To avoid this unexpected result, `mv()` command of Benry::UnixCommand handles two functions in different forms.
|
937
|
+
|
938
|
+
* rename: `mv "foo", "bar"` (error if directory `bar` exists)
|
939
|
+
* move: `mv "foo", to: "bar"` (error if 'bar' is a file or not exist)
|
940
|
+
|
941
|
+
In the same reason, `cp()` and `ln()` of Benry::UnixCommand also requires `to:` option.
|
942
|
+
|
943
|
+
|
944
|
+
|
945
|
+
### How to use in Rakefile?
|
946
|
+
|
947
|
+
File: Rakefile
|
948
|
+
|
949
|
+
```ruby
|
950
|
+
require 'benry/unixcommand' # !!!!!
|
951
|
+
include Benry::UnixCommand # !!!!!
|
952
|
+
Rake::DSL.prepend Benry::UnixCommand # !!!!!
|
953
|
+
|
954
|
+
task :example do
|
955
|
+
## invoke commands defined in Benry::UnixCommand, not in Rake nor fileutils.rb
|
956
|
+
mkdir :p, "foo/bar/baz"
|
957
|
+
here = Dir.pwd()
|
958
|
+
pushd "foo/bar/baz" do
|
959
|
+
output = capture2 "pwd"
|
960
|
+
puts output.sub(here+"/", "")
|
961
|
+
end
|
962
|
+
end
|
963
|
+
```
|
964
|
+
|
965
|
+
Result:
|
966
|
+
|
967
|
+
```terminal
|
968
|
+
[localhost]$ rake example
|
969
|
+
$ mkdir -p foo/bar/baz
|
970
|
+
$ pushd foo/bar/baz
|
971
|
+
$ pwd
|
972
|
+
foo/bar/baz
|
973
|
+
$ popd # back to /home/yourname
|
974
|
+
```
|
975
|
+
|
976
|
+
|
977
|
+
|
978
|
+
### How to change prompt string?
|
979
|
+
|
980
|
+
File: ex-prompt1.rb
|
981
|
+
|
982
|
+
```ruby
|
983
|
+
require 'benry/unixcommand'
|
984
|
+
include Benry::UnixCommand
|
985
|
+
|
986
|
+
def prompt() # !!!!!
|
987
|
+
"myname@localhost> " # !!!!!
|
988
|
+
end # !!!!!
|
989
|
+
|
990
|
+
sys "date"
|
991
|
+
```
|
992
|
+
|
993
|
+
Result:
|
994
|
+
|
995
|
+
```terminal
|
996
|
+
[localhost]$ ruby ex-prompt1.rb
|
997
|
+
myname@localhost> date
|
998
|
+
Wed Jan 15 20:23:07 UTC 2021
|
999
|
+
```
|
1000
|
+
|
1001
|
+
|
1002
|
+
|
1003
|
+
### How to make prompt colored?
|
1004
|
+
|
1005
|
+
<!--
|
1006
|
+
File: ex-prompt2.rb
|
1007
|
+
-->
|
1008
|
+
|
1009
|
+
```ruby
|
1010
|
+
require 'benry/unixcommand'
|
1011
|
+
include Benry::UnixCommand
|
1012
|
+
|
1013
|
+
def prompt()
|
1014
|
+
s = "myname@localhost>"
|
1015
|
+
"\e[31m#{s}\e[0m " # red
|
1016
|
+
#"\e[32m#{s}\e[0m " # green
|
1017
|
+
#"\e[33m#{s}\e[0m " # yellow
|
1018
|
+
#"\e[34m#{s}\e[0m " # blue
|
1019
|
+
#"\e[35m#{s}\e[0m " # magenta
|
1020
|
+
#"\e[36m#{s}\e[0m " # cyan
|
1021
|
+
#"\e[37m#{s}\e[0m " # white
|
1022
|
+
#"\e[1m#{s}\e[0m " # bold
|
1023
|
+
#"\e[2m#{s}\e[0m " # gray
|
1024
|
+
end
|
1025
|
+
|
1026
|
+
sys "date"
|
1027
|
+
```
|
1028
|
+
|
1029
|
+
|
1030
|
+
|
1031
|
+
### How to disable command echoback?
|
1032
|
+
|
1033
|
+
File: ex-quiet1.rb
|
1034
|
+
|
1035
|
+
```ruby
|
1036
|
+
require 'benry/unixcommand'
|
1037
|
+
include Benry::UnixCommand
|
1038
|
+
|
1039
|
+
## disable temporarily
|
1040
|
+
echoback_off do
|
1041
|
+
sys "date"
|
1042
|
+
end
|
1043
|
+
|
1044
|
+
## disable globally
|
1045
|
+
$BENRY_ECHOBACK = false # !!!!!
|
1046
|
+
sys "date"
|
1047
|
+
```
|
1048
|
+
|
1049
|
+
Result:
|
1050
|
+
|
1051
|
+
```terminal
|
1052
|
+
$ ruby ex-quiet1.rb
|
1053
|
+
Wed Jan 1 22:29:55 UTC 2020 # no echoback, only output
|
1054
|
+
Wed Jan 1 22:29:55 UTC 2020 # no echoback, only output
|
1055
|
+
```
|
1056
|
+
|
1057
|
+
|
1058
|
+
|
1059
|
+
## License and Copyright
|
1060
|
+
|
1061
|
+
$License: MIT License $
|
1062
|
+
|
1063
|
+
$Copyright: copyright(c) 2021 kwatch@gmail.com $
|