benry-unixcommand 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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 $