{"id":13994,"date":"2020-08-16T00:57:40","date_gmt":"2020-08-15T15:57:40","guid":{"rendered":"https:\/\/its-more.jp\/ja_jp\/?p=13994"},"modified":"2020-08-20T09:38:32","modified_gmt":"2020-08-20T00:38:32","slug":"gshell%e3%83%ad%e3%82%b4%e3%81%ae%e6%a4%9c%e8%a8%8e","status":"publish","type":"post","link":"https:\/\/its-more.jp\/ja_jp\/?p=13994","title":{"rendered":"GShell 0.1.1 \u2212 \u30ed\u30b4\u6848\u3068CSS\u6574\u5099"},"content":{"rendered":"\n<p>\u5e83\u5831\uff1a\u305d\u308c\u3067\u3054\u4f9d\u983c\u306eGShell\u306e\u30ed\u30b4\u3067\u3059\u304c\u3001\u7b2c\u30bc\u30ed\u6b21\u6848\u3068\u3057\u3066\u3053\u306e\u3088\u3046\u306a\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-Logo00.png\" alt=\"\" class=\"wp-image-13995\" width=\"193\" height=\"95\"\/><\/figure><\/div>\n\n\n\n<p>\u793e\u9577\uff1a\u3044\u3044\u611f\u3058\u3067\u3059\u304c\u3001S\u304c\u3082\u3046\u3061\u3087\u3068\u3075\u304f\u3088\u304b\u306a\u611f\u3058\u304c\u826f\u3044\u3067\u3059\u3002<\/p>\n\n\n\n<p>\u5e83\u5831\uff1a\u305d\u308c\u304c\u306a\u304b\u306a\u304b\u3001\u305d\u306e\u3088\u3046\u306a\u30d5\u30a9\u30f3\u30c8\u304c\u306a\u3044\u3093\u3067\u3059\u3088\u306d\u2026\u3000macOS\u7248\u306e\u30d1\u30ef\u30dd\u3067\u306f\u3046\u3093\u3056\u308a\u3059\u308b\u307b\u3069\u30ed\u30b4\u304c\u3042\u3063\u3066\u3001\u305d\u306e\u4e2d\u306730\u304f\u3089\u3044\u306f\u63a2\u3057\u305f\u306e\u3067\u3059\u304c\u2026<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-0.48.31.png\" alt=\"\" class=\"wp-image-13996\" width=\"127\" height=\"108\" srcset=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-0.48.31.png 506w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-0.48.31-300x257.png 300w\" sizes=\"(max-width: 127px) 100vw, 127px\" \/><\/figure><\/div>\n\n\n\n<p>\u793e\u9577\uff1a\u3084\u306f\u308aCourier \u306f\u826f\u3044\u3067\u3059\u304c\u3001\u30a8\u30eb\u304c\u3061\u3087\u3063\u3068\u3046\u3056\u3044\u3068\u3044\u3046\u304b\u3001\u9593\u5ef6\u3073\u611f\u304c\u3069\u3046\u3082\u3067\u3059\u306d\u3002<\/p>\n\n\n\n<p>\u958b\u767a\uff1a\u308f\u305f\u3057\u306f\u30a8\u30eb\u30a8\u30eb\u306e ll \u304c\u659c\u4f53\u3067 \/\/ \u307f\u305f\u3044\u306b\u898b\u3048\u308b\u306e\u304c\u597d\u304d\u3067\u3059\u306d\u3002\u5b9f\u306f\u3001\/\/ \u3068\u3044\u3046\u30b7\u30f3\u30dc\u30eb\u306f\u3001\u3086\u308b\u3044\u9806\u5e8f\u95a2\u4fc2\u3082\u3042\u308a\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u7684\u306a\u9023\u7d50\u95a2\u4fc2\u3092\u8868\u3059\u306e\u306b\u826f\u3044\u8a18\u53f7\u3060\u3068\u601d\u3063\u3066\u3044\u307e\u3057\u3066\u3001\u4f55\u304b\u306b\u4f7f\u3044\u305f\u3044\u3068\u601d\u3063\u3066\u3044\u308b\u306e\u3067\u3059\u3002<\/p>\n\n\n\n<p>\u57fa\u76e4\uff1a\u3068\u3053\u308d\u3067\u540d\u524d\u306f\u3044\u3063\u305d<em>GOshell <\/em>\u306b\u3059\u308b\u3068\u304b\uff1f\u7565\u3057\u3066gosh\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GOshell-logo00.png\" alt=\"\" class=\"wp-image-13999\" width=\"197\" height=\"95\"\/><\/figure><\/div>\n\n\n\n<p>\u958b\u767a\uff1a\u307e\u3042\u3001\u6700\u7d42\u7684\u306b\u306f\u5fc5\u305a\u3057\u3082Go\u306b\u3079\u3063\u305f\u308a\u3092\u76ee\u6307\u3057\u3066\u3044\u308b\u308f\u3051\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u306e\u3067\u2026\u3000G\u306f general \u307f\u305f\u3044\u306a\u3064\u3082\u308a\u3067\u3044\u305f\u3044\u3068\u601d\u3063\u3066\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u793e\u9577\uff1a\u305d\u3046\u3044\u3046\u610f\u5473\u3067\u306f Unified \u3068\u304b Universal \u306e U \u3082\u597d\u304d\u3067\u3059\u306d\u3002 <\/p>\n\n\n\n<p>\u958b\u767a\uff1aush\u3002\u6bcd\u97f3\u5b57\u304c\u304b\u3089\u59cb\u307e\u308b\u3068\u3053\u308d\u304c\u3069\u3046\u304b\u306a\u3068\u306f\u601d\u3044\u307e\u3059\u306d\u3002<\/p>\n\n\n\n<p>\u57fa\u76e4\uff1a\u3067\u306f bush \u3068\u304b push \u3068\u304b zush \u3068\u304b:-)<\/p>\n\n\n\n<p>\u793e\u9577\uff1a\u307e\u3042\u5f53\u9762\u306f gsh \u3067\u884c\u304d\u307e\u3059\u304b\u3002<\/p>\n\n\n\n<p>\u5e83\u5831\uff1a\u30b0\u30ec\u30fc\u30b9\u30b1\u30fc\u30eb\u3067\u30b0\u30e9\u30c7\u30fc\u30b7\u30e7\u30f3\u3068\u3044\u3046\u6848\u3082\u8003\u3048\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-Logo03.png\" alt=\"\" class=\"wp-image-14004\" width=\"194\" height=\"95\"\/><\/figure><\/div>\n\n\n\n<p>\u793e\u9577\uff1a\u60aa\u304f\u306a\u3044\u3068\u601d\u3044\u307e\u3059\u304c\u2026\u3000\u3053\u308c\u3067\u3082PNG\u30675KB\u3042\u308b\u3093\u3067\u3059\u306d\u3002<\/p>\n\n\n\n<p>\u5e83\u5831\uff1a\u3061\u3087\u3063\u3068\u304a\u30d5\u30e9\u30f3\u30b9\u7cfb\u3068\u304b\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-Logo04.png\" alt=\"\" class=\"wp-image-14006\" width=\"194\" height=\"95\"\/><\/figure><\/div>\n\n\n\n<p>\u958b\u767a\uff1a\u591a\u8272\u3060\u3068\u30a4\u30f3\u30d1\u30af\u30c8\u306f\u3042\u308a\u307e\u3059\u306d\u3002<\/p>\n\n\n\n<p>\u57fa\u76e4\uff1a\u3067\u3082\u3001G\u307e\u3067\u304c\u30d1\u30af\u30ea\u3060\u3068\u3059\u308b\u3068\u3001G\u306e\u90e8\u5206\u306f Go\u30d6\u30eb\u30fc\u306e\u307b\u3046\u304c\u826f\u3044\u306e\u3067\u306f\u3002<\/p>\n\n\n\n<p>\u5e83\u5831\uff1a\u3067\u306fG\u306f\u9752\u3067\u3001\u5f8c\u306f\u304a\u3068\u306a\u3057\u3081\u306b\u6848\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-Logo05.png\" alt=\"\" class=\"wp-image-14008\" width=\"194\" height=\"95\"\/><\/figure><\/div>\n\n\n\n<p>\u5e83\u5831\uff1a\u3042\u308b\u3044\u306f\u3082\u3046\u3001\u3044\u3063\u305d\u30df\u30ad\u30cf\u30a6\u30b9\u6848\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-Logo06.png\" alt=\"\" class=\"wp-image-14009\" width=\"194\" height=\"95\"\/><\/figure><\/div>\n\n\n\n<p>\u793e\u9577\uff1a\u3046\u30fc\u3093\u3001\u3068\u308a\u3042\u3048\u305a\u304a\u3068\u306a\u3057\u3081\u306eLogo005.png\u3067\u884c\u304d\u307e\u3057\u3087\u3046\u3002\u3059\u307f\u308c\u8272\u304c\u597d\u304d\u3060\u3057\u3002<\/p>\n\n\n\n<p class=\"has-text-align-center\">\uff0a\u3000\uff0a\u3000\uff0a<\/p>\n\n\n\n<p>\u958b\u767a\uff1a\u30ed\u30b4\u3092\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306b\u5f35\u308a\u8fbc\u3093\u3067\u307f\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u57fa\u76e4\uff1a\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306b\uff1f<\/p>\n\n\n\n<p>\u958b\u767a\uff1agsh.go \u306f\u3001\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u517c\u3001\u30db\u30fc\u30e0\u30da\u30fc\u30b8\u517c\u3001\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u517c\u3001\u2026\u3067\u3059\u3002Go\u8a00\u8a9e\u306b\u5f93\u3063\u3066\u3044\u307e\u3059\u304c\u3001HTML\u3067\u3082\u3042\u308a\u307e\u3059\u3002\u62e1\u5f35\u5b50\u3092\u5909\u3048\u308b\u3068\u898b\u3048\u65b9\u304c\u5909\u308f\u308a\u307e\u3059\u3002\u305f\u3068\u3048\u3070\u30b9\u30de\u30db\u3067\u898b\u308b\u3068\u3053\u3046\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-version-0.1.1-2020-08-16-SatoxITS-577x1024.jpeg\" alt=\"\" class=\"wp-image-14011\" width=\"144\" height=\"256\" srcset=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-version-0.1.1-2020-08-16-SatoxITS-577x1024.jpeg 577w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-version-0.1.1-2020-08-16-SatoxITS-169x300.jpeg 169w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/GShell-version-0.1.1-2020-08-16-SatoxITS.jpeg 640w\" sizes=\"(max-width: 144px) 100vw, 144px\" \/><\/figure><\/div>\n\n\n\n<p>\u958b\u767a\uff1a\u30c7\u30b9\u30af\u30c8\u30c3\u30d7\u3067\u898b\u308b\u3068\u3053\u3046\u3067\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.28.52.png\" alt=\"\" class=\"wp-image-14013\" width=\"449\" height=\"351\" srcset=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.28.52.png 897w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.28.52-300x234.png 300w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.28.52-768x600.png 768w\" sizes=\"(max-width: 449px) 100vw, 449px\" \/><\/figure><\/div>\n\n\n\n<p>\u793e\u9577\uff1a\u30ed\u30b4\u306f\u5358\u8272\u306e\u7b2c\u30bc\u30ed\u6b21\u6848\u306a\u3093\u3067\u3059\u306d\u3002<\/p>\n\n\n\n<p>\u958b\u767a\uff1a\u73fe\u5728\u306e\u30da\u30fc\u30b8\u69cb\u6210\u306e\u4e2d\u3067\u306f\u53ce\u307e\u308a\u304c\u826f\u3044\u304b\u3068\u3002\u3068\u308a\u3042\u3048\u305a\u3067\u3059\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.42.14-646x1024.png\" alt=\"\" class=\"wp-image-14021\" width=\"323\" height=\"512\" srcset=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.42.14-646x1024.png 646w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.42.14-189x300.png 189w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.42.14-768x1217.png 768w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.42.14.png 897w\" sizes=\"(max-width: 323px) 100vw, 323px\" \/><\/figure><\/div>\n\n\n\n<p>\u958b\u767a\uff1a\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3067\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u306e\u5404\u90e8\u306b\u30b8\u30e3\u30f3\u30d7\u3059\u308b\u4ed5\u639b\u3051\u3067\u3059\u304c\u3001\u3053\u308c\u306f\u81ea\u5206\u3067\u3082\u30b3\u30fc\u30c9\u3092\u30d6\u30e9\u30a6\u30ba\u3059\u308b\u306e\u306b\u3082\u4fbf\u5229\u3057\u3066\u3044\u307e\u3059\u3002 \u53c2\u7167\u3057\u3066\u3044\u308b\u30d1\u30c3\u30b1\u30fc\u30b8\u306b\u3082\u5373\u98db\u3079\u307e\u3059\u3002\u30bd\u30fc\u30b9\u30d7\u30ed\u30e9\u30e0\u3082\u80fd\u52d5\u7684\u306b\u30cf\u30a4\u30d1\u30fc\u30c6\u30ad\u30b9\u30c8\u3067\u3042\u308b\u3079\u304d\u3060\u3068\u601d\u3044\u307e\u3059\u3002\u30a2\u30af\u30c6\u30a3\u30d6\u30bd\u30fc\u30b9\u30b3\u30fc\u30c9\u3068\u3067\u3082\u8a00\u3044\u307e\u3057\u3087\u3046\u304b\u3002<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" src=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.43.39-612x1024.png\" alt=\"\" class=\"wp-image-14022\" width=\"306\" height=\"512\" srcset=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.43.39-612x1024.png 612w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.43.39-179x300.png 179w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.43.39-768x1284.png 768w, https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/Screen-Shot-2020-08-16-at-17.43.39.png 897w\" sizes=\"(max-width: 306px) 100vw, 306px\" \/><\/figure><\/div>\n\n\n\n<p>\u793e\u9577\uff1aWiki\u3092\u7de8\u96c6\u3059\u308b\u3088\u3046\u306b\u3057\u3066\u30d7\u30ed\u30b0\u30e9\u30e0\u304c\u66f8\u3051\u308b\u3068\u826f\u3044\u306e\u304b\u3082\u77e5\u308c\u307e\u305b\u306d\u3093\u3002\u308f\u305f\u3057\u7684\u306b\u306fPDF\u306b\u3057\u3066\u7f72\u540d\u3059\u308b\u306e\u304c\u697d\u3067\u826f\u3044\u3067\u3059(^-^)<\/p>\n\n\n\n<p>\u958b\u767a\uff1aWordPress\u306b\u3082\u62e1\u5f35HTML\u3068\u3057\u3066\u8cbc\u308a\u4ed8\u3051\u3089\u308c\u308b\u3068\u826f\u3044\u306e\u3067\u3059\u304c\u2026\u3000\u3042\u3042\u305d\u3046\u304b\u3001HTML\u306e\u30bd\u30fc\u30b9\u3092\u8868\u793a\u3057\u3066\u5168\u9078\u629e\u3057\u3066\u30ab\u30b9\u30bf\u30e0HTML\u306b\u8cbc\u308a\u4ed8\u3051\u308c\u3070\u3088\u3044\u306e\u3067\u3059\u306d\u3002\u305f\u3060\u2026\u3000CSS\u306b\u30b9\u30b3\u30fc\u30d7\u304c\u7121\u3044\u304b\u3089\u672c\u6587\u306e\u30b9\u30bf\u30a4\u30eb\u307e\u3067\u5909\u308f\u3063\u3061\u3083\u3046\u3068\u8a00\u3046w<\/p>\n\n\n\n<p>\u793e\u9577\uff1a<a href=\"https:\/\/developer.mozilla.org\/ja\/docs\/Web\/HTML\/Element\/iframe\">iframe<\/a> \u306b\u9589\u3058\u8fbc\u3081\u3089\u308c\u308c\u3070\u826f\u3044\u3068\u601d\u3046\u306e\u3067\u3059\u304c\u3002\u30a4\u30f3\u30e9\u30a4\u30f3\u306e\u30c6\u30ad\u30b9\u30c8\u3092iframe\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u306b\u3059\u308b\u65b9\u6cd5\u3063\u3066\u3042\u308b\u3093\u3067\u3059\u304b\u306d\u3002textarea \u7684\u306b\u3002<\/p>\n\n\n\n<p>\u958b\u767a\uff1a\u8feb\u5bb3\u3055\u308c\u3066\u6d88\u3055\u308c\u3066\u3057\u307e\u3063\u305fframe\u3067\u306f\u51fa\u6765\u305f\u3068\u601d\u3046\u3093\u3067\u3059\u304c\u2026<\/p>\n\n\n\n<p>\u793e\u9577\uff1adata URI \u306b\u3059\u308b\u307b\u3069\u5c0f\u3055\u304f\u3082\u7121\u3044\u3067\u3059\u3057\u306d\uff57<\/p>\n\n\n\n<p>\u958b\u767a\uff1a\u8981\u306f\u300cid \u3092\u4ed8\u3051\u305f\u8981\u7d20\u3092\u3053\u3053\u306b\u5c55\u958b\u3059\u308b\u300d\u3068\u3044\u3046\u6a5f\u80fd\u304c\u3042\u308c\u3070\u826f\u3044\u306e\u3067\u3059\u304c\u3002iframe \u3067\u306a\u304f\u3066\u3082\u306a\u3093\u3067\u3082\u3001\u3068\u3044\u3046\u304b iframe \u4ee5\u5916\u306e\u307b\u3046\u304c\u4fbf\u5229\u3067\u3059\u304c\u3002<\/p>\n\n\n\n<p>\u958b\u767a\uff1a\u3068\u3082\u304b\u304f\u3053\u306e\u3001CSS\u306e\u30b9\u30b3\u30fc\u30d7\u3068\u3044\u3046\u304b\u30bb\u30ec\u30af\u30bf\u3068\u3044\u3046\u306e\u304c\u3069\u3046\u3082\u308f\u304b\u3089\u306a\u3044\u3002\u307e\u3068\u3081\u3066\u5404\u65b9\u6cd5\u3068\u3044\u3046\u304b {} \u304c\u5165\u308c\u5b50\u306b\u3067\u304d\u306a\u3044\u306e\u304b\u308f\u304b\u3089\u306a\u306e\u3067\u3001\u30d9\u30bf\u306b\u66f8\u3044\u3066\u307f\u307e\u3057\u305f\u3002\u3053\u308c\u3067\u4f55\u3068\u304b\u3002<\/p>\n\n\n\n<p>\u793e\u9577\uff1a\u3046\u3093\u3046\u3093\u3002\u3088\u308d\u3057\u3044\u3093\u3058\u3083\u306a\u3044\u3067\u3057\u3087\u3046\u304b\u3002\u3067\u306f\u3053\u308c\u3092\u5370\u5237\u3057\u3066\u7d42\u4e86\u3057\u305f\u3044\u3068\u601d\u3044\u307e\u3059\u3002<\/p>\n\n\n\n<p>-- 2020-0816 SatoxITS<\/p>\n\n\n\n<div class=\"wp-block-file\"><a href=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/\u7d9aGShell-0.1.1-\u30fc-\u30ed\u30b3\u3099\u306e\u691c\u8a0e-\u2013-\u682a\u5f0f\u4f1a\u793e-ITS-more.pdf\">\u7d9aGShell-0.1.1-\u30fc-\u30ed\u30b3\u3099\u306e\u691c\u8a0e-\u2013-\u682a\u5f0f\u4f1a\u793e-ITS-more<\/a><a href=\"https:\/\/its-more.jp\/ja_jp\/wp-content\/uploads\/2020\/08\/\u7d9aGShell-0.1.1-\u30fc-\u30ed\u30b3\u3099\u306e\u691c\u8a0e-\u2013-\u682a\u5f0f\u4f1a\u793e-ITS-more.pdf\" class=\"wp-block-file__button\" download>\u30c0\u30a6\u30f3\u30ed\u30fc\u30c9<\/a><\/div>\n\n\n\n\/\/ <span id=gsh>\n\/*\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>GShell-0.1.1 by SatoxITS<\/title>\n<link rel=icon href=GShell-Logo05icon.png>\n<header height=100px>\n<div align=right><note>GShell version 0.1.1 \/\/ 2020-08-16 \/\/ SatoxITS<\/note><\/div>\n<\/header>\n<h2>GShell \/\/ a General purpose Shell built on the top of Golang<\/h2>\n*\/\n\/*\n<details id=overview><summary>Overview<\/summary><pre>\nTo be written\n<\/pre><\/details>\n*\/\n\/*\n<details id=index><summary>Index<\/summary>\n<pre onclick=\"document.getElementById('gocode').open=true;\">\n\nImplementation\n\tStructures\n\t\t<a href=#import>import<\/a>\n\t\t<a href=#struct>struct<\/a>\n\tMain functions\n\t\t<a href=#comexpansion>str-expansion<\/a>\t\/\/ macro processor\n\t\t<a href=#finder>finder<\/a>\t\t\/\/ builtin find + du\n\t\t<a href=#grep>grep<\/a>\t\t\/\/ builtin grep + wc + cksum + ...\n\t\t<a href=#plugin>plugin<\/a>\t\t\/\/ plugin commands\n\t\t<a href=#ex-commands>system<\/a>\t\t\/\/ external commands\n\t\t<a href=#builtin>builtin<\/a>\t\t\/\/ builtin commands\n\t\t<a href=#network>network<\/a>\t\t\/\/ socket handler\n\t\t<a href=#redirect>redirect<\/a>\t\/\/ StdIn\/Out redireciton\n\t\t<a href=#history>history<\/a>\t\t\/\/ command history\n\t\t<a href=#rusage>rusage<\/a>\t\t\/\/ resouce usage\n\t\t<a href=#getline>getline<\/a>\t\t\/\/ line editor\n\t\t<a href=#interpreter>interpreter<\/a>\t\/\/ command interpreter\n\t\t<a href=#main>main<\/a><pre>\n<\/details>\n*\/\n\/\/<details id=gocode><summary>Source Code<\/summary>\n\/\/<pre onclick=\"document.getElementById('gocode').open=false;\">\n\/\/ gsh - Go lang based Shell\n\/\/ (c) 2020 ITS more Co., Ltd.\n\/\/ 2020-0807 created by SatoxITS (sato@its-more.jp)\n\npackage main \/\/ gsh main\n\/\/ Documents: <a href=https:\/\/golang.org\/pkg\/>Packages<\/a>\n\/\/ <a name=import>Impoted packages<\/a>\nimport (\n\t\"fmt\"\t\t\/\/ <a href=https:\/\/golang.org\/pkg\/fmt\/>fmt<\/a>\n\t\"strings\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/strings\/>strings<\/a>\n\t\"strconv\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/strconv\/>strconv<\/a>\n\t\"sort\"\t\t\/\/ <a href=https:\/\/golang.org\/pkg\/sort\/>sort<\/a>\n\t\"time\"\t\t\/\/ <a href=https:\/\/golang.org\/pkg\/time\/>time<\/a>\n\t\"bufio\"\t\t\/\/ <a href=https:\/\/golang.org\/pkg\/bufio\/>bufio<\/a>\n\t\"io\/ioutil\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/io\/ioutil\/>ioutil<\/a>\n\t\"os\"\t\t\/\/ <a href=https:\/\/golang.org\/pkg\/os\/>os<\/a>\n\t\"syscall\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/syscall\/>syscall<\/a>\n\t\"plugin\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/plugin\/>plugin<\/a>\n\t\"net\"\t\t\/\/ <a href=https:\/\/golang.org\/pkg\/net\/>net<\/a>\n\t\"net\/http\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/net\/http\/>http<\/a>\n\t\/\/\"html\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/html\/>html<\/a>\n\t\"path\/filepath\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/path\/filepath\/>filepath<\/a>\n\t\"go\/types\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/go\/types\/>types<\/a>\n\t\"go\/token\"\t\/\/ <a href=https:\/\/golang.org\/pkg\/go\/token\/>token<\/a>\n)\n\nvar VERSION = \"gsh\/0.1.1 (2020-0816a)\"\nvar LINESIZE = (8*1024)\nvar PATHSEP = \":\" \/\/ should be \";\" in Windows\nvar DIRSEP = \"\/\" \/\/ canbe \\ in Windows\nvar PROMPT = \"> \"\nvar GSH_HOME = \".gsh\" \/\/ under home directory\n\n\/\/ -xX logging control\n\/\/ --A-- all\n\/\/ --I-- info.\n\/\/ --D-- debug\n\/\/ --W-- warning\n\/\/ --E-- error\n\/\/ --F-- fatal error\n\n\/\/ <a name=struct>Structures<\/a>\ntype GCommandHistory struct {\n\tStartAt\t\ttime.Time \/\/ command line execution started at\n\tEndAt\t\ttime.Time \/\/ command line execution ended at\n\tResCode\t\tint       \/\/ exit code of (external command)\n\tCmdError\terror     \/\/ error string\n\tOutData\t\t*os.File  \/\/ output of the command\n\tFoundFile\t[]string  \/\/ output - result of ufind\n\tRusagev\t\t[2]syscall.Rusage \/\/ Resource consumption, CPU time or so\n\tCmdId\t\tint       \/\/ maybe with identified with arguments or impact\n\t\t\t          \/\/ redireciton commands should not be the CmdId\n\tWorkDir\t\tstring    \/\/ working directory at start\n\tCmdLine\t\tstring    \/\/ command line\n}\ntype GChdirHistory struct {\n\tDir\t\tstring\n\tMovedAt\t\ttime.Time\n}\ntype CmdMode struct {\n\tBackGround\tbool\n}\ntype PluginInfo struct {\n\tSpec\t\t*plugin.Plugin\n\tAddr\t\tplugin.Symbol\n\tName\t\tstring \/\/ maybe relative\n\tPath\t\tstring \/\/ this is in Plugin but hidden\n}\ntype GshContext struct {\n\tStartDir\tstring\t\/\/ the current directory at the start\n\tGetLine\t\tstring\t\/\/ gsh-getline command as a input line editor\n\tChdirHistory\t[]GChdirHistory \/\/ the 1st entry is wd at the start\n\tgshPA\t\tsyscall.ProcAttr\n\tCommandHistory\t[]GCommandHistory\n\tCmdCurrent\tGCommandHistory\n\tBackGround\tbool\n\tBackGroundJobs\t[]int\n\tLastRusage\tsyscall.Rusage\n\tGshHomeDir\tstring\n\tTerminalId\tint\n\tCmdTrace\tbool\n\tPluginFuncs\t[]PluginInfo\n}\n\nfunc strBegins(str, pat string)(bool){\n\tif 0 < len(str){\n\t\tyes := str[0:len(pat)] == pat\n\t\t\/\/fmt.Printf(\"--D-- strBegins(%v,%v)=%v\\n\",str,pat,yes)\n\t\treturn yes\n\t}\n\t\/\/fmt.Printf(\"--D-- strBegins(%v,%v)=%v\\n\",str,pat,false)\n\treturn false\n}\nfunc isin(what string, list []string) bool {\n\tfor _, v := range list  {\n\t\tif v == what {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\nfunc isinX(what string,list[]string)(int){\n\tfor i,v := range list {\n\t\tif v == what {\n\t\t\treturn i\n\t\t}\n\t}\n\treturn -1\n}\n\nfunc env(opts []string) {\n\tenv := os.Environ()\n\tif isin(\"-s\", opts){\n\t\tsort.Slice(env, func(i,j int) bool {\n\t\t\treturn env[i] < env[j]\n\t\t})\n\t}\n\tfor _, v := range env {\n\t\tfmt.Printf(\"%v\\n\",v)\n\t}\n}\n\n\/\/ - rewriting should be context dependent\n\/\/ - should postpone until the real point of evaluation\n\/\/ - should rewrite only known notation of symobl\nfunc scanInt(str string)(val int,leng int){\n\tleng = -1\n\tfor i,ch := range str {\n\t\tif '0' <= ch && ch <= '9' {\n\t\t\tleng = i+1\n\t\t}else{\n\t\t\tbreak\n\t\t}\n\t}\n\tif 0 < leng {\n\t\tival,_ := strconv.Atoi(str[0:leng])\n\t\treturn ival,leng\n\t}else{\n\t\treturn 0,0\n\t}\n}\nfunc substHistory(gshCtx *GshContext,str string,i int,rstr string)(leng int,rst string){\n\tif len(str[i+1:]) == 0 {\n\t\treturn 0,rstr\n\t}\n\thi := 0\n\thistlen := len(gshCtx.CommandHistory)\n\tif str[i+1] == '!' {\n\t\thi = histlen - 1\n\t\tleng = 1\n\t}else{\n\t\thi,leng = scanInt(str[i+1:])\n\t\tif leng == 0 {\n\t\t\treturn 0,rstr\n\t\t}\n\t\tif hi < 0 {\n\t\t\thi = histlen + hi\n\t\t}\n\t}\n\tif 0 <= hi && hi < histlen {\n\t\t\/\/fmt.Printf(\"--D-- %v(%c)\\n\",str[i+leng:],str[i+leng])\n\t\tif 1 < len(str[i+leng:]) && str[i+leng:][1] == 'f' {\n\t\t\tleng += 1\n\t\t\txlist := []string{}\n\t\t\tlist := gshCtx.CommandHistory[hi].FoundFile\n\t\t\tfor _,v := range list {\n\t\t\t\t\/\/list[i] = escapeWhiteSP(v)\n\t\t\t\txlist = append(xlist,escapeWhiteSP(v))\n\t\t\t}\n\t\t\t\/\/rstr += strings.Join(list,\" \")\n\t\t\trstr += strings.Join(xlist,\" \")\n\t\t}else{\n\t\t\trstr += gshCtx.CommandHistory[hi].CmdLine\n\t\t}\n\t}else{\n\t\tleng = 0\n\t}\n\treturn leng,rstr\n}\nfunc escapeWhiteSP(str string)(string){\n\tif len(str) == 0 {\n\t\treturn \"\\\\z\" \/\/ empty, to be ignored\n\t}\n\trstr := \"\"\n\tfor _,ch := range str {\n\t\tswitch ch {\n\t\t\tcase '\\\\': rstr += \"\\\\\\\\\"\n\t\t\tcase ' ': rstr += \"\\\\s\"\n\t\t\tcase '\\t': rstr += \"\\\\t\"\n\t\t\tcase '\\r': rstr += \"\\\\r\"\n\t\t\tcase '\\n': rstr += \"\\\\n\"\n\t\t\tdefault: rstr += string(ch)\n\t\t}\n\t}\n\treturn rstr\n}\nfunc unescapeWhiteSP(str string)(string){ \/\/ strip original escapes\n\trstr := \"\"\n\tfor i := 0; i < len(str); i++ {\n\t\tch := str[i]\n\t\tif ch == '\\\\' {\n\t\t\tif i+1 < len(str) {\n\t\t\t\tswitch str[i+1] {\n\t\t\t\t\tcase 'z':\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trstr += string(ch)\n\t}\n\treturn rstr\n}\nfunc unescapeWhiteSPV(strv []string)([]string){ \/\/ strip original escapes\n\tustrv := []string{}\n\tfor _,v := range strv {\n\t\tustrv = append(ustrv,unescapeWhiteSP(v))\n\t}\n\treturn ustrv\n}\n\n\/\/ <a name=comexpansion>str-expansion<\/a>\n\/\/ - this should be a macro processor\nfunc strsubst(gshCtx *GshContext,str string,histonly bool) string {\n\trstr := \"\"\n\tinEsc := 0 \/\/ escape characer mode \n\tfor i := 0; i < len(str); i++ {\n\t\t\/\/fmt.Printf(\"--D--Subst %v:%v\\n\",i,str[i:])\n\t\tch := str[i]\n\t\tif inEsc == 0 {\n\t\t\tif ch == '!' {\n\t\t\t\tleng,xrstr := substHistory(gshCtx,str,i,rstr)\n\t\t\t\tif 0 < leng {\n\t\t\t\t\ti += leng\n\t\t\t\t\trstr = xrstr\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\t\t\tswitch ch {\n\t\t\t\tcase '\\\\': inEsc = '\\\\'; continue\n\t\t\t\tcase '%':  inEsc = '%';  continue\n\t\t\t\tcase '$':\n\t\t\t}\n\t\t}\n\t\tswitch inEsc {\n\t\tcase '\\\\':\n\t\t\tswitch ch {\n\t\t\t\tcase '\\\\': ch = '\\\\'\n\t\t\t\tcase 's': ch = ' '\n\t\t\t\tcase 't': ch = '\\t'\n\t\t\t\tcase 'r': ch = '\\r'\n\t\t\t\tcase 'n': ch = '\\n'\n\t\t\t\tcase 'z': inEsc = 0; continue \/\/ empty, to be ignored\n\t\t\t}\n\t\t\tinEsc = 0 \n\t\tcase '%':\n\t\t\tswitch {\n\t\t\t\tcase ch == '%': ch = '%'\n\t\t\t\tcase ch == 'T':\n\t\t\t\t\trstr = rstr + time.Now().Format(time.Stamp)\n\t\t\t\t\tcontinue;\n\t\t\t\tdefault:\n\t\t\t\t\t\/\/ postpone the interpretation\n\t\t\t\t\trstr = rstr + \"%\" + string(ch)\n\t\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tinEsc = 0\n\t\t}\n\t\trstr = rstr + string(ch)\n\t}\n\treturn rstr\n}\nfunc showFileInfo(path string, opts []string) {\n\tif isin(\"-l\",opts) || isin(\"-ls\",opts) {\n\t\tfi, _ := os.Stat(path)\n\t\tmod := fi.ModTime()\n\t\tdate := mod.Format(time.Stamp)\n\t\tfmt.Printf(\"%v %8v %s \",fi.Mode(),fi.Size(),date)\n\t}\n\tfmt.Printf(\"%s\",path)\n\tif isin(\"-sp\",opts) {\n\t\tfmt.Printf(\" \")\n\t}else\n\tif ! isin(\"-n\",opts) {\n\t\tfmt.Printf(\"\\n\")\n\t}\n}\nfunc userHomeDir()(string,bool){\n\t\/*\n\thomedir,_ = os.UserHomeDir() \/\/ not implemented in older Golang\n\t*\/\n\thomedir,found := os.LookupEnv(\"HOME\")\n\t\/\/fmt.Printf(\"--I-- HOME=%v(%v)\\n\",homedir,found)\n\tif !found {\n\t\treturn \"\/tmp\",found\n\t}\n\treturn homedir,found\n}\n\nfunc toFullpath(path string) (fullpath string) {\n\tif path[0] == '\/' {\n\t\treturn path\n\t}\n\tpathv := strings.Split(path,DIRSEP)\n\tswitch {\n\tcase pathv[0] == \".\":\n\t\tpathv[0], _ = os.Getwd()\n\tcase pathv[0] == \"..\": \/\/ all ones should be interpreted\n\t\tcwd, _ := os.Getwd()\n\t\tppathv := strings.Split(cwd,DIRSEP)\n\t\tpathv[0] = strings.Join(ppathv,DIRSEP)\n\tcase pathv[0] == \"~\":\n\t\tpathv[0],_ = userHomeDir()\n\tdefault:\n\t\tcwd, _ := os.Getwd()\n\t\tpathv[0] = cwd + DIRSEP + pathv[0]\n\t}\n\treturn strings.Join(pathv,DIRSEP)\n}\n\nfunc IsRegFile(path string)(bool){\n\tfi, err := os.Stat(path)\n\tif err == nil {\n\t\tfm := fi.Mode()\n\t\treturn fm.IsRegular();\n\t}\n\treturn false\n}\n\n\/\/ <a name=grep>grep<\/a>\n\/\/ \"lines\", \"lin\" or \"lnp\" for \"(text) line processor\" or \"scanner\"\n\/\/ a*,!ab,c, ... sequentioal combination of patterns\n\/\/ what \"LINE\" is should be definable\n\/\/ generic line-by-line processing\n\/\/ grep [-v]\n\/\/ cat -n -v\n\/\/ uniq [-c]\n\/\/ tail -f\n\/\/ sed s\/x\/y\/ or awk\n\/\/ grep with line count like wc\n\/\/ rewrite contents if specified\nfunc xGrep(gshCtx GshContext,path string,rexpv[]string)(int){\n\tfile, err := os.OpenFile(path,os.O_RDONLY,0)\n\tif err != nil {\n\t\tfmt.Printf(\"--E-- grep %v (%v)\\n\",path,err)\n\t\treturn -1\n\t}\n\tdefer file.Close()\n\tif gshCtx.CmdTrace { fmt.Printf(\"--I-- grep %v %v\\n\",path,rexpv) }\n\t\/\/reader := bufio.NewReaderSize(file,LINESIZE)\n\treader := bufio.NewReaderSize(file,80)\n\tli := 0\n\tfound := 0\n\tfor li = 0; ; li++ {\n\t\tline, err := reader.ReadString('\\n')\n\t\tif len(line) <= 0 {\n\t\t\tbreak\n\t\t}\n\t\tif 150 < len(line) {\n\t\t\t\/\/ maybe binary\n\t\t\tbreak;\n\t\t}\n\t\tif err != nil {\n\t\t\tbreak\n\t\t}\n\t\tif 0 <= strings.Index(string(line),rexpv[0]) {\n\t\t\tfound += 1\n\t\t\tfmt.Printf(\"%s:%d: %s\",path,li,line)\n\t\t}\n\t}\n\t\t\/\/fmt.Printf(\"total %d lines %s\\n\",li,path)\n\t\/\/if( 0 < found ){ fmt.Printf(\"((found %d lines %s))\\n\",found,path); }\n\treturn found\n}\n\n\/\/ <a name=finder>Finder<\/a>\n\/\/ finding files with it name and contents\n\/\/ file names are ORed\n\/\/ show the content with %x fmt list\n\/\/ ls -R\n\/\/ tar command by adding output\ntype fileSum struct {\n\tErr\tint64\t\/\/ access error or so\n\tSize\tint64\t\/\/ content size\n\tDupSize\tint64\t\/\/ content size from hard links\n\tBlocks\tint64\t\/\/ number of blocks (of 512 bytes)\n\tDupBlocks int64\t\/\/ Blocks pointed from hard links\n\tHLinks\tint64\t\/\/ hard links\n\tWords\tint64\n\tLines\tint64\n\tFiles\tint64\n\tDirs\tint64\t\/\/ the num. of directories\n\tSymLink\tint64\n\tFlats\tint64\t\/\/ the num. of flat files\n\tMaxDepth\tint64\n\tMaxNamlen\tint64\t\/\/ max. name length\n\tnextRepo\ttime.Time\n}\nfunc showFusage(dir string,fusage *fileSum){\n\tbsume := float64(((fusage.Blocks-fusage.DupBlocks)\/2)*1024)\/1000000.0\n\t\/\/bsumdup := float64((fusage.Blocks\/2)*1024)\/1000000.0\n\n\tfmt.Printf(\"%v: %v files (%vd %vs %vh) %.6f MB (%.2f MBK)\\n\",\n\t\tdir,\n\t\tfusage.Files,\n\t\tfusage.Dirs,\n\t\tfusage.SymLink,\n\t\tfusage.HLinks,\n\t\tfloat64(fusage.Size)\/1000000.0,bsume);\n}\nconst (\n\tS_IFMT    = 0170000\n\tS_IFCHR   = 0020000\n\tS_IFDIR   = 0040000\n\tS_IFREG   = 0100000\n\tS_IFLNK   = 0120000\n\tS_IFSOCK  = 0140000\n)\nfunc cumFinfo(fsum *fileSum, path string, staterr error, fstat syscall.Stat_t, argv[]string,verb bool)(*fileSum){\n\tnow := time.Now()\n\tif time.Second <= now.Sub(fsum.nextRepo) {\n\t\tif !fsum.nextRepo.IsZero(){\n\t\t\ttstmp := now.Format(time.Stamp)\n\t\t\tshowFusage(tstmp,fsum)\n\t\t}\n\t\tfsum.nextRepo = now.Add(time.Second)\n\t}\n\tif staterr != nil {\n\t\tfsum.Err += 1\n\t\treturn fsum\n\t}\n\tfsum.Files += 1\n\tif 1 < fstat.Nlink {\n\t\t\/\/ must count only once...\n\t\t\/\/ at least ignore ones in the same directory\n\t\t\/\/if finfo.Mode().IsRegular() {\n\t\tif (fstat.Mode & S_IFMT) == S_IFREG {\n\t\t\tfsum.HLinks += 1\n\t\t\tfsum.DupBlocks += int64(fstat.Blocks)\n\t\t\t\/\/fmt.Printf(\"---Dup HardLink %v %s\\n\",fstat.Nlink,path)\n\t\t}\n\t}\n\t\/\/fsum.Size += finfo.Size()\n\tfsum.Size += fstat.Size\n\tfsum.Blocks += int64(fstat.Blocks) \n\t\/\/if verb { fmt.Printf(\"(%8dBlk) %s\",fstat.Blocks\/2,path) }\n\tif isin(\"-ls\",argv){\n\t\t\/\/if verb { fmt.Printf(\"%4d %8d \",fstat.Blksize,fstat.Blocks) }\n\/\/\t\tfmt.Printf(\"%d\\t\",fstat.Blocks\/2)\n\t}\n\t\/\/if finfo.IsDir()\n\tif (fstat.Mode & S_IFMT) == S_IFDIR {\n\t\tfsum.Dirs += 1\n\t}\n\t\/\/if (finfo.Mode() & os.ModeSymlink) != 0 \n\tif (fstat.Mode & S_IFMT) == S_IFLNK {\n\t\t\/\/if verb { fmt.Printf(\"symlink(%v,%s)\\n\",fstat.Mode,finfo.Name()) }\n\t\t\/\/{ fmt.Printf(\"symlink(%o,%s)\\n\",fstat.Mode,finfo.Name()) }\n\t\tfsum.SymLink += 1\n\t}\n\treturn fsum\n}\nfunc xxFindEntv(gshCtx GshContext,depth int,total *fileSum,dir string, dstat syscall.Stat_t, ei int, entv []string,npatv[]string,argv[]string)(GshContext,*fileSum){\n\tnols := isin(\"-grep\",argv)\n\t\/\/ sort entv\n\t\/*\n\tif isin(\"-t\",argv){\n\t\tsort.Slice(filev, func(i,j int) bool {\n\t\t\treturn 0 < filev[i].ModTime().Sub(filev[j].ModTime())\n\t\t})\n\t}\n\t*\/\n\t\t\/*\n\t\tif isin(\"-u\",argv){\n\t\t\tsort.Slice(filev, func(i,j int) bool {\n\t\t\t\treturn 0 < filev[i].AccTime().Sub(filev[j].AccTime())\n\t\t\t})\n\t\t}\n\t\tif isin(\"-U\",argv){\n\t\t\tsort.Slice(filev, func(i,j int) bool {\n\t\t\t\treturn 0 < filev[i].CreatTime().Sub(filev[j].CreatTime())\n\t\t\t})\n\t\t}\n\t\t*\/\n\t\/*\n\tif isin(\"-S\",argv){\n\t\tsort.Slice(filev, func(i,j int) bool {\n\t\t\treturn filev[j].Size() < filev[i].Size()\n\t\t})\n\t}\n\t*\/\n\tfor _,filename := range entv {\n\t\tfor _,npat := range npatv {\n\t\t\tmatch := true\n\t\t\tif npat == \"*\" {\n\t\t\t\tmatch = true\n\t\t\t}else{\n\t\t\t\tmatch, _ = filepath.Match(npat,filename)\n\t\t\t}\n\t\t\tpath := dir + DIRSEP + filename\n\t\t\tif !match {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tvar fstat syscall.Stat_t\n\t\t\tstaterr := syscall.Lstat(path,&fstat)\n\t\t\tif staterr != nil {\n\t\t\t\tif !isin(\"-w\",argv){fmt.Printf(\"ufind: %v\\n\",staterr) }\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif isin(\"-du\",argv) && (fstat.Mode & S_IFMT) == S_IFDIR {\n\t\t\t\t\/\/ should not show size of directory in \"-du\" mode ...\n\t\t\t}else\n\t\t\tif !nols && !isin(\"-s\",argv) && (!isin(\"-du\",argv) || isin(\"-a\",argv)) {\n\t\t\t\tif isin(\"-du\",argv) {\n\t\t\t\t\tfmt.Printf(\"%d\\t\",fstat.Blocks\/2)\n\t\t\t\t}\n\t\t\t\tshowFileInfo(path,argv)\n\t\t\t}\n\t\t\tif true { \/\/ && isin(\"-du\",argv)\n\t\t\t\ttotal = cumFinfo(total,path,staterr,fstat,argv,false)\n\t\t\t}\n\t\t\t\/*\n\t\t\tif isin(\"-wc\",argv) {\n\t\t\t}\n\t\t\t*\/\n\t\t\tx := isinX(\"-grep\",argv); \/\/ -grep will be convenient like -ls\n\t\t\tif 0 <= x && x+1 <= len(argv) { \/\/ -grep will be convenient like -ls\n\t\t\t\tif IsRegFile(path){\n\t\t\t\t\tfound := xGrep(gshCtx,path,argv[x+1:])\n\t\t\t\t\tif 0 < found {\n\t\t\t\t\t\tfoundv := gshCtx.CmdCurrent.FoundFile\n\t\t\t\t\t\tif len(foundv) < 10 {\n\t\t\t\t\t\t\tgshCtx.CmdCurrent.FoundFile =\n\t\t\t\t\t\t\tappend(gshCtx.CmdCurrent.FoundFile,path)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif !isin(\"-r0\",argv) { \/\/ -d 0 in du, -depth n in find\n\t\t\t\t\/\/total.Depth += 1\n\t\t\t\tif (fstat.Mode & S_IFMT) == S_IFLNK {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif dstat.Rdev != fstat.Rdev {\n\t\t\t\t\tfmt.Printf(\"--I-- don't follow differnet device %v(%v) %v(%v)\\n\",\n\t\t\t\t\t\tdir,dstat.Rdev,path,fstat.Rdev)\n\t\t\t\t}\n\t\t\t\tif (fstat.Mode & S_IFMT) == S_IFDIR {\n\t\t\t\t\tgshCtx,total = xxFind(gshCtx,depth+1,total,path,npatv,argv)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn gshCtx,total\n}\nfunc xxFind(gshCtx GshContext,depth int,total *fileSum,dir string,npatv[]string,argv[]string)(GshContext,*fileSum){\n\tnols := isin(\"-grep\",argv)\n\tdirfile,oerr := os.OpenFile(dir,os.O_RDONLY,0)\n\tif oerr == nil {\n\t\t\/\/fmt.Printf(\"--I-- %v(%v)[%d]\\n\",dir,dirfile,dirfile.Fd())\n\t\tdefer dirfile.Close()\n\t}else{\n\t}\n\n\tprev := *total\n\tvar dstat syscall.Stat_t\n\tstaterr := syscall.Lstat(dir,&dstat) \/\/ should be flstat\n\n\tif staterr != nil {\n\t\tif !isin(\"-w\",argv){ fmt.Printf(\"ufind: %v\\n\",staterr) }\n\t\treturn gshCtx,total\n\t}\n\t\t\/\/filev,err := ioutil.ReadDir(dir)\n\t\t\/\/_,err := ioutil.ReadDir(dir) \/\/ ReadDir() heavy and bad for huge directory\n\t\t\/*\n\t\tif err != nil {\n\t\t\tif !isin(\"-w\",argv){ fmt.Printf(\"ufind: %v\\n\",err) }\n\t\t\treturn total\n\t\t}\n\t\t*\/\n\tif depth == 0 {\n\t\ttotal = cumFinfo(total,dir,staterr,dstat,argv,true)\n\t\tif !nols && !isin(\"-s\",argv) && (!isin(\"-du\",argv) || isin(\"-a\",argv)) {\n\t\t\tshowFileInfo(dir,argv)\n\t\t}\n\t}\n\t\/\/ it it is not a directory, just scan it and finish\n\n\tfor ei := 0; ; ei++ {\n\t\tentv,rderr := dirfile.Readdirnames(8*1024)\n\t\tif len(entv) == 0 || rderr != nil {\n\t\t\t\/\/if rderr != nil { fmt.Printf(\"[%d] len=%d (%v)\\n\",ei,len(entv),rderr) }\n\t\t\tbreak\n\t\t}\n\t\tif 0 < ei {\n\t\t\tfmt.Printf(\"--I-- xxFind[%d] %d large-dir: %s\\n\",ei,len(entv),dir)\n\t\t}\n\t\tgshCtx,total = xxFindEntv(gshCtx,depth,total,dir,dstat,ei,entv,npatv,argv)\n\t}\n\tif isin(\"-du\",argv) {\n\t\t\/\/ if in \"du\" mode\n\t\tfmt.Printf(\"%d\\t%s\\n\",(total.Blocks-prev.Blocks)\/2,dir)\n\t}\n\treturn gshCtx,total\n}\n\n\/\/ {ufind|fu|ls} [Files] [\/\/ Names] [-- Expressions]\n\/\/  Files is \".\" by default\n\/\/  Names is \"*\" by default\n\/\/  Expressions is \"-print\" by default for \"ufind\", or -du for \"fu\" command\nfunc xFind(gshCtx GshContext,argv[]string)(GshContext){\n\tif 0 < len(argv) && strBegins(argv[0],\"?\"){\n\t\tshowFound(gshCtx,argv)\n\t\treturn gshCtx\n\t}\n\tvar total = fileSum{}\n\tnpats := []string{}\n\tfor _,v := range argv {\n\t\tif 0 < len(v) && v[0] != '-' {\n\t\t\tnpats = append(npats,v)\n\t\t}\n\t\tif v == \"\/\/\" { break }\n\t\tif v == \"--\" { break }\n\t\tif v == \"-grep\" { break }\n\t\tif v == \"-ls\" { break }\n\t}\n\tif len(npats) == 0 {\n\t\tnpats = []string{\"*\"}\n\t}\n\tcwd := \".\"\n\t\/\/ if to be fullpath ::: cwd, _ := os.Getwd()\n\tif len(npats) == 0 { npats = []string{\"*\"} }\n\tgshCtx,fusage := xxFind(gshCtx,0,&total,cwd,npats,argv)\n\tif !isin(\"-grep\",argv) {\n\t\tshowFusage(\"total\",fusage)\n\t}\n\treturn gshCtx\n}\n\nfunc showFiles(files[]string){\n\tsp := \"\"\n\tfor i,file := range files {\n\t\tif 0 < i { sp = \" \" } else { sp = \"\" }\n\t\tfmt.Printf(sp+\"%s\",escapeWhiteSP(file))\n\t}\n}\nfunc showFound(gshCtx GshContext, argv[]string){\n\tfor i,v := range gshCtx.CommandHistory {\n\t\tif 0 < len(v.FoundFile) {\n\t\t\tfmt.Printf(\"!%d (%d) \",i,len(v.FoundFile))\n\t\t\tif isin(\"-ls\",argv){\n\t\t\t\tfmt.Printf(\"\\n\")\n\t\t\t\tfor _,file := range v.FoundFile {\n\t\t\t\t\tfmt.Printf(\"\") \/\/sub number?\n\t\t\t\t\tshowFileInfo(file,argv)\n\t\t\t\t}\n\t\t\t}else{\n\t\t\t\tshowFiles(v.FoundFile)\n\t\t\t\tfmt.Printf(\"\\n\")\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc showMatchFile(filev []os.FileInfo, npat,dir string, argv[]string)(string,bool){\n\tfname := \"\"\n\tfound := false\n\tfor _,v := range filev {\n\t\tmatch, _ := filepath.Match(npat,(v.Name()))\n\t\tif match {\n\t\t\tfname = v.Name()\n\t\t\tfound = true\n\t\t\t\/\/fmt.Printf(\"[%d] %s\\n\",i,v.Name())\n\t\t\tshowIfExecutable(fname,dir,argv)\n\t\t}\n\t}\n\treturn fname,found\n}\nfunc showIfExecutable(name,dir string,argv[]string)(ffullpath string,ffound bool){\n\tvar fullpath string\n\tif strBegins(name,DIRSEP){\n\t\tfullpath = name\n\t}else{\n\t\tfullpath = dir + DIRSEP + name\n\t}\n\tfi, err := os.Stat(fullpath)\n\tif err != nil {\n\t\tfullpath = dir + DIRSEP + name + \".go\"\n\t\tfi, err = os.Stat(fullpath)\n\t}\n\tif err == nil {\n\t\tfm := fi.Mode()\n\t\tif fm.IsRegular() {\n\t\t  \/\/ R_OK=4, W_OK=2, X_OK=1, F_OK=0\n\t\t  if syscall.Access(fullpath,5) == nil {\n\t\t\tffullpath = fullpath\n\t\t\tffound = true\n\t\t\tif ! isin(\"-s\", argv) {\n\t\t\t\tshowFileInfo(fullpath,argv)\n\t\t\t}\n\t\t  }\n\t\t}\n\t}\n\treturn ffullpath, ffound\n}\nfunc which(list string, argv []string) (fullpathv []string, itis bool){\n\tif len(argv) <= 1 {\n\t\tfmt.Printf(\"Usage: which comand [-s] [-a] [-ls]\\n\")\n\t\treturn []string{\"\"}, false\n\t}\n\tpath := argv[1]\n\tif strBegins(path,\"\/\") {\n\t\t\/\/ should check if excecutable?\n\t\t_,exOK := showIfExecutable(path,\"\/\",argv)\n\t\tfmt.Printf(\"--D-- %v exOK=%v\\n\",path,exOK)\n\t\treturn []string{path},exOK\n\t}\n\tpathenv, efound := os.LookupEnv(list)\n\tif ! efound {\n\t\tfmt.Printf(\"--E-- which: no \\\"%s\\\" environment\\n\",list)\n\t\treturn []string{\"\"}, false\n\t}\n\tshowall := isin(\"-a\",argv) || 0 <= strings.Index(path,\"*\")\n\tdirv := strings.Split(pathenv,PATHSEP)\n\tffound := false\n\tffullpath := path\n\tfor _, dir := range dirv {\n\t\tif 0 <= strings.Index(path,\"*\") { \/\/ by wild-card\n\t\t\tlist,_ := ioutil.ReadDir(dir)\n\t\t\tffullpath, ffound = showMatchFile(list,path,dir,argv)\n\t\t}else{\n\t\t\tffullpath, ffound = showIfExecutable(path,dir,argv)\n\t\t}\n\t\t\/\/if ffound && !isin(\"-a\", argv) {\n\t\tif ffound && !showall {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn []string{ffullpath}, ffound\n}\n\nfunc stripLeadingWSParg(argv[]string)([]string){\n\tfor ; 0 < len(argv); {\n\t\tif len(argv[0]) == 0 {\n\t\t\targv = argv[1:]\n\t\t}else{\n\t\t\tbreak\n\t\t}\n\t}\n\treturn argv\n}\nfunc xEval(argv []string, nlend bool){\n\targv = stripLeadingWSParg(argv)\n\tif len(argv) == 0 {\n\t\tfmt.Printf(\"eval [%%format] [Go-expression]\\n\")\n\t\treturn\n\t}\n\tpfmt := \"%v\"\n\tif argv[0][0] == '%' {\n\t\tpfmt = argv[0]\n\t\targv = argv[1:]\n\t}\n\tif len(argv) == 0 {\n\t\treturn\n\t}\n\tgocode := strings.Join(argv,\" \");\n\t\/\/fmt.Printf(\"eval [%v] [%v]\\n\",pfmt,gocode)\n\tfset := token.NewFileSet()\n\trval, _ := types.Eval(fset,nil,token.NoPos,gocode)\n\tfmt.Printf(pfmt,rval.Value)\n\tif nlend { fmt.Printf(\"\\n\") }\n}\n\nfunc getval(name string) (found bool, val int) {\n\t\/* should expand the name here *\/\n\tif name == \"gsh.pid\" {\n\t\treturn true, os.Getpid()\n\t}else\n\tif name == \"gsh.ppid\" {\n\t\treturn true, os.Getppid()\n\t}\n\treturn false, 0\n}\n\nfunc echo(argv []string, nlend bool){\n\tfor ai := 1; ai < len(argv); ai++ {\n\t\tif 1 < ai {\n\t\t\tfmt.Printf(\" \");\n\t\t}\n\t\targ := argv[ai]\n\t\tfound, val := getval(arg)\n\t\tif found {\n\t\t\tfmt.Printf(\"%d\",val)\n\t\t}else{\n\t\t\tfmt.Printf(\"%s\",arg)\n\t\t}\n\t}\n\tif nlend {\n\t\tfmt.Printf(\"\\n\");\n\t}\n}\n\nfunc resfile() string {\n\treturn \"gsh.tmp\"\n}\n\/\/var resF *File\nfunc resmap() {\n\t\/\/_ , err := os.OpenFile(resfile(), os.O_RDWR|os.O_CREATE, os.ModeAppend)\n\t\/\/ https:\/\/developpaper.com\/solution-to-golang-bad-file-descriptor-problem\/\n\t_ , err := os.OpenFile(resfile(), os.O_RDWR|os.O_CREATE, 0600)\n\tif err != nil {\n\t\tfmt.Printf(\"refF could not open: %s\\n\",err)\n\t}else{\n\t\tfmt.Printf(\"refF opened\\n\")\n\t}\n}\n\n\/\/ <a name=ex-commands>External commands<\/a>\nfunc excommand(gshCtx GshContext, exec bool, argv []string) (GshContext, bool) {\n\tif gshCtx.CmdTrace { fmt.Printf(\"--I-- excommand[%v](%v)\\n\",exec,argv) }\n\n\tgshPA := gshCtx.gshPA\n\tfullpathv, itis := which(\"PATH\",[]string{\"which\",argv[0],\"-s\"})\n\tif itis == false {\n\t\treturn gshCtx, true\n\t}\n\tfullpath := fullpathv[0]\n\targv = unescapeWhiteSPV(argv)\n\tif 0 < strings.Index(fullpath,\".go\") {\n\t\tnargv := argv \/\/ []string{}\n\t\tgofullpathv, itis := which(\"PATH\",[]string{\"which\",\"go\",\"-s\"})\n\t\tif itis == false {\n\t\t\tfmt.Printf(\"--F-- Go not found\\n\")\n\t\t\treturn gshCtx, true\n\t\t}\n\t\tgofullpath := gofullpathv[0]\n\t\tnargv = []string{ gofullpath, \"run\", fullpath }\n\t\tfmt.Printf(\"--I-- %s {%s %s %s}\\n\",gofullpath,\n\t\t\tnargv[0],nargv[1],nargv[2])\n\t\tif exec {\n\t\t\tsyscall.Exec(gofullpath,nargv,os.Environ())\n\t\t}else{\n\t\t\tpid, _ := syscall.ForkExec(gofullpath,nargv,&gshPA)\n\t\t\tif gshCtx.BackGround {\n\t\t\t\tfmt.Printf(\"--I-- in Background [%d]\\n\",pid)\n\t\t\t\tgshCtx.BackGroundJobs = append(gshCtx.BackGroundJobs,pid)\n\t\t\t}else{\n\t\t\t\trusage := syscall.Rusage {}\n\t\t\t\tsyscall.Wait4(pid,nil,0,&rusage)\n\t\t\t\tgshCtx.LastRusage = rusage\n\t\t\t\tgshCtx.CmdCurrent.Rusagev[1] = rusage\n\t\t\t}\n\t\t}\n\t}else{\n\t\tif exec {\n\t\t\tsyscall.Exec(fullpath,argv,os.Environ())\n\t\t}else{\n\t\t\tpid, _ := syscall.ForkExec(fullpath,argv,&gshPA)\n\t\t\t\/\/fmt.Printf(\"[%d]\\n\",pid); \/\/ '&' to be background\n\t\t\tif gshCtx.BackGround {\n\t\t\t\tfmt.Printf(\"--I-- in Background [%d]\\n\",pid)\n\t\t\t\tgshCtx.BackGroundJobs = append(gshCtx.BackGroundJobs,pid)\n\t\t\t}else{\n\t\t\t\trusage := syscall.Rusage {}\n\t\t\t\tsyscall.Wait4(pid,nil,0,&rusage);\n\t\t\t\tgshCtx.LastRusage = rusage\n\t\t\t\tgshCtx.CmdCurrent.Rusagev[1] = rusage\n\t\t\t}\n\t\t}\n\t}\n\treturn gshCtx, false\n}\n\n\/\/ <a name=builtin>Builtin Commands<\/a>\nfunc sleep(gshCtx GshContext, argv []string) {\n\tif len(argv) < 2 {\n\t\tfmt.Printf(\"Sleep 100ms, 100us, 100ns, ...\\n\")\n\t\treturn\n\t}\n\tduration := argv[1];\n\td, err := time.ParseDuration(duration)\n\tif err != nil {\n\t\td, err = time.ParseDuration(duration+\"s\")\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"duration ? %s (%s)\\n\",duration,err)\n\t\t\treturn\n\t\t}\n\t}\n\t\/\/fmt.Printf(\"Sleep %v\\n\",duration)\n\ttime.Sleep(d)\n\tif 0 < len(argv[2:]) {\n\t\tgshellv(gshCtx, argv[2:])\n\t}\n}\nfunc repeat(gshCtx GshContext, argv []string) {\n\tif len(argv) < 2 {\n\t\treturn\n\t}\n\tstart0 := time.Now()\n\tfor ri,_ := strconv.Atoi(argv[1]); 0 < ri; ri-- {\n\t\tif 0 < len(argv[2:]) {\n\t\t\t\/\/start := time.Now()\n\t\t\tgshellv(gshCtx, argv[2:])\n\t\t\tend := time.Now()\n\t\t\telps := end.Sub(start0);\n\t\t\tif( 1000000000 < elps ){\n\t\t\t\tfmt.Printf(\"(repeat#%d %v)\\n\",ri,elps);\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc gen(gshCtx GshContext, argv []string) {\n\tgshPA := gshCtx.gshPA\n\tif len(argv) < 2 {\n\t\tfmt.Printf(\"Usage: %s N\\n\",argv[0])\n\t\treturn\n\t}\n\t\/\/ should br repeated by \"repeat\" command\n\tcount, _ := strconv.Atoi(argv[1])\n\tfd := gshPA.Files[1] \/\/ Stdout\n\tfile := os.NewFile(fd,\"internalStdOut\")\n\tfmt.Printf(\"--I-- Gen. Count=%d to [%d]\\n\",count,file.Fd())\n\t\/\/buf := []byte{}\n\toutdata := \"0123 5678 0123 5678 0123 5678 0123 5678\\r\"\n\tfor gi := 0; gi < count; gi++ {\n\t\tfile.WriteString(outdata)\n\t}\n\t\/\/file.WriteString(\"\\n\")\n\tfmt.Printf(\"\\n(%d B)\\n\",count*len(outdata));\n\t\/\/file.Close()\n}\n\n\/\/ <a name=network>network<\/a>\n\/\/ -s, -si, -so \/\/ bi-directional, source, sync (maybe socket)\nfunc sconnect(gshCtx GshContext, inTCP bool, argv []string) {\n\tgshPA := gshCtx.gshPA\n\tif len(argv) < 2 {\n\t\tfmt.Printf(\"Usage: -s [host]:[port[.udp]]\\n\")\n\t\treturn\n\t}\n\tremote := argv[1]\n\tif remote == \":\" { remote = \"0.0.0.0:9999\" }\n\n\tif inTCP { \/\/ TCP\n\t\tdport, err := net.ResolveTCPAddr(\"tcp\",remote);\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Address error: %s (%s)\\n\",remote,err)\n\t\t\treturn\n\t\t}\n\t\tconn, err := net.DialTCP(\"tcp\",nil,dport)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Connection error: %s (%s)\\n\",remote,err)\n\t\t\treturn\n\t\t}\n\t\tfile, _ := conn.File();\n\t\tfd := file.Fd()\n\t\tfmt.Printf(\"Socket: connected to %s, socket[%d]\\n\",remote,fd)\n\n\t\tsavfd := gshPA.Files[1]\n\t\tgshPA.Files[1] = fd;\n\t\tgshellv(gshCtx, argv[2:])\n\t\tgshPA.Files[1] = savfd\n\t\tfile.Close()\n\t\tconn.Close()\n\t}else{\n\t\t\/\/dport, err := net.ResolveUDPAddr(\"udp4\",remote);\n\t\tdport, err := net.ResolveUDPAddr(\"udp\",remote);\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Address error: %s (%s)\\n\",remote,err)\n\t\t\treturn\n\t\t}\n\t\t\/\/conn, err := net.DialUDP(\"udp4\",nil,dport)\n\t\tconn, err := net.DialUDP(\"udp\",nil,dport)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Connection error: %s (%s)\\n\",remote,err)\n\t\t\treturn\n\t\t}\n\t\tfile, _ := conn.File();\n\t\tfd := file.Fd()\n\n\t\tar := conn.RemoteAddr()\n\t\t\/\/al := conn.LocalAddr()\n\t\tfmt.Printf(\"Socket: connected to %s [%s], socket[%d]\\n\",\n\t\t\tremote,ar.String(),fd)\n\n\t\tsavfd := gshPA.Files[1]\n\t\tgshPA.Files[1] = fd;\n\t\tgshellv(gshCtx, argv[2:])\n\t\tgshPA.Files[1] = savfd\n\t\tfile.Close()\n\t\tconn.Close()\n\t}\n}\nfunc saccept(gshCtx GshContext, inTCP bool, argv []string) {\n\tgshPA := gshCtx.gshPA\n\tif len(argv) < 2 {\n\t\tfmt.Printf(\"Usage: -ac [host]:[port[.udp]]\\n\")\n\t\treturn\n\t}\n\tlocal := argv[1]\n\tif local == \":\" { local = \"0.0.0.0:9999\" }\n\tif inTCP { \/\/ TCP\n\t\tport, err := net.ResolveTCPAddr(\"tcp\",local);\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Address error: %s (%s)\\n\",local,err)\n\t\t\treturn\n\t\t}\n\t\t\/\/fmt.Printf(\"Listen at %s...\\n\",local);\n\t\tsconn, err := net.ListenTCP(\"tcp\", port)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Listen error: %s (%s)\\n\",local,err)\n\t\t\treturn\n\t\t}\n\t\t\/\/fmt.Printf(\"Accepting at %s...\\n\",local);\n\t\taconn, err := sconn.AcceptTCP()\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Accept error: %s (%s)\\n\",local,err)\n\t\t\treturn\n\t\t}\n\t\tfile, _ := aconn.File()\n\t\tfd := file.Fd()\n\t\tfmt.Printf(\"Accepted TCP at %s [%d]\\n\",local,fd)\n\n\t\tsavfd := gshPA.Files[0]\n\t\tgshPA.Files[0] = fd;\n\t\tgshellv(gshCtx, argv[2:])\n\t\tgshPA.Files[0] = savfd\n\n\t\tsconn.Close();\n\t\taconn.Close();\n\t\tfile.Close();\n\t}else{\n\t\t\/\/port, err := net.ResolveUDPAddr(\"udp4\",local);\n\t\tport, err := net.ResolveUDPAddr(\"udp\",local);\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Address error: %s (%s)\\n\",local,err)\n\t\t\treturn\n\t\t}\n\t\tfmt.Printf(\"Listen UDP at %s...\\n\",local);\n\t\t\/\/uconn, err := net.ListenUDP(\"udp4\", port)\n\t\tuconn, err := net.ListenUDP(\"udp\", port)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"Listen error: %s (%s)\\n\",local,err)\n\t\t\treturn\n\t\t}\n\t\tfile, _ := uconn.File()\n\t\tfd := file.Fd()\n\t\tar := uconn.RemoteAddr()\n\t\tremote := \"\"\n\t\tif ar != nil { remote = ar.String() }\n\t\tif remote == \"\" { remote = \"?\" }\n\n\t\t\/\/ not yet received\n\t\t\/\/fmt.Printf(\"Accepted at %s [%d] <- %s\\n\",local,fd,\"\")\n\n\t\tsavfd := gshPA.Files[0]\n\t\tgshPA.Files[0] = fd;\n\t\tsavenv := gshPA.Env\n\t\tgshPA.Env = append(savenv, \"REMOTE_HOST=\"+remote)\n\t\tgshellv(gshCtx, argv[2:])\n\t\tgshPA.Env = savenv\n\t\tgshPA.Files[0] = savfd\n\n\t\tuconn.Close();\n\t\tfile.Close();\n\t}\n}\n\n\/\/ empty line command\nfunc xPwd(gshCtx GshContext, argv[]string){\n\t\/\/ execute context command, pwd + date\n\t\/\/ context notation, representation scheme, to be resumed at re-login\n\tcwd, _ := os.Getwd()\n\tswitch {\n\tcase isin(\"-a\",argv):\n\t\txChdirHistory(gshCtx,argv)\n\tcase isin(\"-ls\",argv):\n\t\tshowFileInfo(cwd,argv)\n\tdefault:\n\t\tfmt.Printf(\"%s\\n\",cwd)\n\tcase isin(\"-v\",argv): \/\/ obsolete emtpy command\n\t\tt := time.Now()\n\t\tdate := t.Format(time.UnixDate)\n\t\texe, _ := os.Executable()\n\t\thost, _ := os.Hostname()\n\t\tfmt.Printf(\"{PWD=\\\"%s\\\"\",cwd)\n\t\tfmt.Printf(\" HOST=\\\"%s\\\"\",host)\n\t\tfmt.Printf(\" DATE=\\\"%s\\\"\",date)\n\t\tfmt.Printf(\" TIME=\\\"%s\\\"\",t.String())\n\t\tfmt.Printf(\" PID=\\\"%d\\\"\",os.Getpid())\n\t\tfmt.Printf(\" EXE=\\\"%s\\\"\",exe)\n\t\tfmt.Printf(\"}\\n\")\n\t}\n}\n\n\/\/ <a name=history>History<\/a>\n\/\/ these should be browsed and edited by HTTP browser\n\/\/ show the time of command with -t and direcotry with -ls\n\/\/ openfile-history, sort by -a -m -c\n\/\/ sort by elapsed time by -t -s\n\/\/ search by \"more\" like interface\n\/\/ edit history\n\/\/ sort history, and wc or uniq\n\/\/ CPU and other resource consumptions\n\/\/ limit showing range (by time or so)\n\/\/ export \/ import history\nfunc xHistory(gshCtx GshContext, argv []string) (rgshCtx GshContext) {\n\tfor i, v := range gshCtx.CommandHistory {\n\t\t\/\/ exclude commands not to be listed by default\n\t\t\/\/ internal commands may be suppressed by default\n\t\tif v.CmdLine == \"\" && !isin(\"-a\",argv) {\n\t\t\tcontinue;\n\t\t}\n\t\tif !isin(\"-n\",argv){ \/\/ like \"fc\"\n\t\t\tfmt.Printf(\"!%-3d \",i)\n\t\t}\n\t\tif isin(\"-v\",argv){\n\t\t\tfmt.Println(v) \/\/ should be with it date\n\t\t}else{\n\t\t\tif isin(\"-l\",argv) || isin(\"-l0\",argv) {\n\t\t\t\telps := v.EndAt.Sub(v.StartAt);\n\t\t\t\tstart := v.StartAt.Format(time.Stamp)\n\t\t\t\tfmt.Printf(\"%s %11v\/t \",start,elps)\n\t\t\t}\n\t\t\tif isin(\"-l\",argv) && !isin(\"-l0\",argv){\n\t\t\t\tfmt.Printf(\"%v\",Rusagef(\"%t %u %s\",argv,v.Rusagev))\n\t\t\t}\n\t\t\tif isin(\"-ls\",argv){\n\t\t\t\tfmt.Printf(\"@%s \",v.WorkDir)\n\t\t\t\t\/\/ show the FileInfo of the output command??\n\t\t\t}\n\t\t\tfmt.Printf(\"%s\",v.CmdLine)\n\t\t\tfmt.Printf(\"\\n\")\n\t\t}\n\t}\n\treturn gshCtx\n}\n\/\/ !n - history index\nfunc searchHistory(gshCtx GshContext, gline string) (string, bool, bool){\n\tif gline[0] == '!' {\n\t\thix, err := strconv.Atoi(gline[1:])\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"--E-- (%s : range)\\n\",hix)\n\t\t\treturn \"\", false, true\n\t\t}\n\t\tif hix < 0 || len(gshCtx.CommandHistory) <= hix {\n\t\t\tfmt.Printf(\"--E-- (%d : out of range)\\n\",hix)\n\t\t\treturn \"\", false, true\n\t\t}\n\t\treturn gshCtx.CommandHistory[hix].CmdLine, false, false\n\t}\n\t\/\/ search\n\t\/\/for i, v := range gshCtx.CommandHistory {\n\t\/\/}\n\treturn gline, false, false\n}\n\n\/\/ temporary adding to PATH environment\n\/\/ cd name -lib for LD_LIBRARY_PATH\n\/\/ chdir with directory history (date + full-path)\n\/\/ -s for sort option (by visit date or so)\nfunc xChdirHistory(gshCtx GshContext, argv []string){\n\tfor i, v := range gshCtx.ChdirHistory {\n\t\tfmt.Printf(\"!%d \",i)\n\t\tfmt.Printf(\"%v \",v.MovedAt.Format(time.Stamp))\n\t\tshowFileInfo(v.Dir,argv)\n\t}\n}\nfunc xChdir(gshCtx GshContext, argv []string) (rgshCtx GshContext) {\n\tcdhist := gshCtx.ChdirHistory\n\tif isin(\"?\",argv ) || isin(\"-t\",argv) {\n\t\txChdirHistory(gshCtx,argv)\n\t\treturn gshCtx\n\t}\n\tpwd, _ := os.Getwd()\n\tdir := \"\"\n\tif len(argv) <= 1 {\n\t\tdir = toFullpath(\"~\")\n\t}else{\n\t\tdir = argv[1]\n\t}\n\tif strBegins(dir,\"!\") {\n\t\tif dir == \"!0\" {\n\t\t\tdir = gshCtx.StartDir\n\t\t}else\n\t\tif dir == \"!!\" {\n\t\t\tindex := len(cdhist) - 1\n\t\t\tif 0 < index { index -= 1 }\n\t\t\tdir = cdhist[index].Dir\n\t\t}else{\n\t\t\tindex, err := strconv.Atoi(dir[1:])\n\t\t\tif err != nil {\n\t\t\t\tfmt.Printf(\"--E-- xChdir(%v)\\n\",err)\n\t\t\t\tdir = \"?\"\n\t\t\t}else\n\t\t\tif len(gshCtx.ChdirHistory) <= index {\n\t\t\t\tfmt.Printf(\"--E-- xChdir(history range error)\\n\")\n\t\t\t\tdir = \"?\"\n\t\t\t}else{\n\t\t\t\tdir = cdhist[index].Dir\n\t\t\t}\n\t\t}\n\t}\n\tif dir != \"?\" {\n\t\terr := os.Chdir(dir)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"--E-- xChdir(%s)(%v)\\n\",argv[1],err)\n\t\t}else{\n\t\t\tcwd, _ := os.Getwd()\n\t\t\tif cwd != pwd {\n\t\t\t\thist1 := GChdirHistory { }\n\t\t\t\thist1.Dir = cwd\n\t\t\t\thist1.MovedAt = time.Now()\n\t\t\t\tgshCtx.ChdirHistory = append(cdhist,hist1)\n\t\t\t}\n\t\t}\n\t}\n\tif isin(\"-ls\",argv){\n\t\tcwd, _ := os.Getwd()\n\t\tshowFileInfo(cwd,argv);\n\t}\n\treturn gshCtx\n}\nfunc TimeValSub(tv1 *syscall.Timeval, tv2 *syscall.Timeval){\n\t*tv1 = syscall.NsecToTimeval(tv1.Nano() - tv2.Nano())  \n}\nfunc RusageSubv(ru1, ru2 [2]syscall.Rusage)([2]syscall.Rusage){\n\tTimeValSub(&ru1[0].Utime,&ru2[0].Utime)\n\tTimeValSub(&ru1[0].Stime,&ru2[0].Stime)\n\tTimeValSub(&ru1[1].Utime,&ru2[1].Utime)\n\tTimeValSub(&ru1[1].Stime,&ru2[1].Stime)\n\treturn ru1\n}\nfunc TimeValAdd(tv1 syscall.Timeval, tv2 syscall.Timeval)(syscall.Timeval){\n\ttvs := syscall.NsecToTimeval(tv1.Nano() + tv2.Nano())  \n\treturn tvs\n}\n\/*\nfunc RusageAddv(ru1, ru2 [2]syscall.Rusage)([2]syscall.Rusage){\n\tTimeValAdd(ru1[0].Utime,ru2[0].Utime)\n\tTimeValAdd(ru1[0].Stime,ru2[0].Stime)\n\tTimeValAdd(ru1[1].Utime,ru2[1].Utime)\n\tTimeValAdd(ru1[1].Stime,ru2[1].Stime)\n\treturn ru1\n}\n*\/\n\n\/\/ <a name=rusage>Resource Usage<\/a>\nfunc Rusagef(fmtspec string, argv []string, ru [2]syscall.Rusage)(string){\n\tut := TimeValAdd(ru[0].Utime,ru[1].Utime)\n\tst := TimeValAdd(ru[0].Stime,ru[1].Stime)\n\tfmt.Printf(\"%d.%06ds\/u \",ut.Sec,ut.Usec) \/\/ru[1].Utime.Sec,ru[1].Utime.Usec)\n\tfmt.Printf(\"%d.%06ds\/s \",st.Sec,st.Usec) \/\/ru[1].Stime.Sec,ru[1].Stime.Usec)\n\treturn \"\"\n}\nfunc Getrusagev()([2]syscall.Rusage){\n\tvar ruv = [2]syscall.Rusage{}\n\tsyscall.Getrusage(syscall.RUSAGE_SELF,&ruv[0])\n\tsyscall.Getrusage(syscall.RUSAGE_CHILDREN,&ruv[1])\n\treturn ruv\n}\nfunc showRusage(what string,argv []string, ru *syscall.Rusage){\n\tfmt.Printf(\"%s: \",what);\n\tfmt.Printf(\"Usr=%d.%06ds\",ru.Utime.Sec,ru.Utime.Usec)\n\tfmt.Printf(\" Sys=%d.%06ds\",ru.Stime.Sec,ru.Stime.Usec)\n\tfmt.Printf(\" Rss=%vB\",ru.Maxrss)\n\tif isin(\"-l\",argv) {\n\t\tfmt.Printf(\" MinFlt=%v\",ru.Minflt)\n\t\tfmt.Printf(\" MajFlt=%v\",ru.Majflt)\n\t\tfmt.Printf(\" IxRSS=%vB\",ru.Ixrss)\n\t\tfmt.Printf(\" IdRSS=%vB\",ru.Idrss)\n\t\tfmt.Printf(\" Nswap=%vB\",ru.Nswap)\n\tfmt.Printf(\" Read=%v\",ru.Inblock)\n\tfmt.Printf(\" Write=%v\",ru.Oublock)\n\t}\n\tfmt.Printf(\" Snd=%v\",ru.Msgsnd)\n\tfmt.Printf(\" Rcv=%v\",ru.Msgrcv)\n\t\/\/if isin(\"-l\",argv) {\n\t\tfmt.Printf(\" Sig=%v\",ru.Nsignals)\n\t\/\/}\n\tfmt.Printf(\"\\n\");\n}\nfunc xTime(gshCtx GshContext, argv[]string)(GshContext,bool){\n\tif 2 <= len(argv){\n\t\tgshCtx.LastRusage = syscall.Rusage{}\n\t\trusagev1 := Getrusagev()\n\t\txgshCtx, fin := gshellv(gshCtx,argv[1:])\n\t\trusagev2 := Getrusagev()\n\t\tgshCtx = xgshCtx\n\t\tshowRusage(argv[1],argv,&gshCtx.LastRusage)\n\t\trusagev := RusageSubv(rusagev2,rusagev1)\n\t\tshowRusage(\"self\",argv,&rusagev[0])\n\t\tshowRusage(\"chld\",argv,&rusagev[1])\n\t\treturn gshCtx, fin\n\t}else{\n\t\trusage:= syscall.Rusage {}\n\t\tsyscall.Getrusage(syscall.RUSAGE_SELF,&rusage)\n\t\tshowRusage(\"self\",argv, &rusage)\n\t\tsyscall.Getrusage(syscall.RUSAGE_CHILDREN,&rusage)\n\t\tshowRusage(\"chld\",argv, &rusage)\n\t\treturn gshCtx, false\n\t}\n}\nfunc xJobs(gshCtx GshContext, argv[]string){\n\tfmt.Printf(\"%d Jobs\\n\",len(gshCtx.BackGroundJobs))\n\tfor ji, pid := range gshCtx.BackGroundJobs {\n\t\t\/\/wstat := syscall.WaitStatus {0}\n\t\trusage := syscall.Rusage {}\n\t\t\/\/wpid, err := syscall.Wait4(pid,&wstat,syscall.WNOHANG,&rusage);\n\t\twpid, err := syscall.Wait4(pid,nil,syscall.WNOHANG,&rusage);\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"--E-- %%%d [%d] (%v)\\n\",ji,pid,err)\n\t\t}else{\n\t\t\tfmt.Printf(\"%%%d[%d](%d)\\n\",ji,pid,wpid)\n\t\t\tshowRusage(\"chld\",argv,&rusage)\n\t\t}\n\t}\n}\nfunc inBackground(gshCtx GshContext, argv[]string)(GshContext,bool){\n\tif gshCtx.CmdTrace { fmt.Printf(\"--I-- inBackground(%v)\\n\",argv) }\n\tgshCtx.BackGround = true \/\/ set background option\n\txfin := false\n\tgshCtx, xfin = gshellv(gshCtx,argv)\n\tgshCtx.BackGround = false\n\treturn gshCtx,xfin\n}\n\/\/ -o file without command means just opening it and refer by #N\n\/\/ should be listed by \"files\" comnmand\nfunc xOpen(gshCtx GshContext, argv[]string)(GshContext){\n\tvar pv = []int{-1,-1}\n\terr := syscall.Pipe(pv)\n\tfmt.Printf(\"--I-- pipe()=[#%d,#%d](%v)\\n\",pv[0],pv[1],err)\n\treturn gshCtx\n}\nfunc fromPipe(gshCtx GshContext, argv[]string)(GshContext){\n\treturn gshCtx\n}\nfunc xClose(gshCtx GshContext, argv[]string)(GshContext){\n\treturn gshCtx\n}\n\n\/\/ <a name=redirect>redirect<\/a>\nfunc redirect(gshCtx GshContext, argv[]string)(GshContext,bool){\n\tif len(argv) < 2 {\n\t\treturn gshCtx, false\n\t}\n\n\tcmd := argv[0]\n\tfname := argv[1]\n\tvar file *os.File = nil\n\n\tfdix := 0\n\tmode := os.O_RDONLY\n\n\tswitch {\n\tcase cmd == \"-i\" || cmd == \"<\":\n\t\tfdix = 0\n\t\tmode = os.O_RDONLY\n\tcase cmd == \"-o\" || cmd == \">\":\n\t\tfdix = 1\n\t\tmode = os.O_RDWR | os.O_CREATE\n\tcase cmd == \"-a\" || cmd == \">>\":\n\t\tfdix = 1\n\t\tmode = os.O_RDWR | os.O_CREATE | os.O_APPEND\n\t}\n\tif fname[0] == '#' {\n\t\tfd, err := strconv.Atoi(fname[1:])\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"--E-- (%v)\\n\",err)\n\t\t\treturn gshCtx, false\n\t\t}\n\t\tfile = os.NewFile(uintptr(fd),\"MaybePipe\")\n\t}else{\n\t\txfile, err := os.OpenFile(argv[1], mode, 0600)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"--E-- (%s)\\n\",err)\n\t\t\treturn gshCtx, false\n\t\t}\n\t\tfile = xfile\n\t}\n\tgshPA := gshCtx.gshPA\n\tsavfd := gshPA.Files[fdix]\n\tgshPA.Files[fdix] = file.Fd()\n\tfmt.Printf(\"--I-- Opened [%d] %s\\n\",file.Fd(),argv[1])\n\tgshCtx, _ = gshellv(gshCtx, argv[2:])\n\tgshPA.Files[fdix] = savfd\n\n\treturn gshCtx, false\n}\n\n\/\/fmt.Fprintf(res, \"GShell Status: %q\", html.EscapeString(req.URL.Path))\nfunc httpHandler(res http.ResponseWriter, req *http.Request){\n\tpath := req.URL.Path\n\tfmt.Printf(\"--I-- Got HTTP Request(%s)\\n\",path)\n\t{\n\t\tgshCtx, _ :=  setupGshContext()\n\t\tfmt.Printf(\"--I-- %s\\n\",path[1:])\n\t\tgshCtx, _ = tgshelll(gshCtx,path[1:])\n\t}\n\tfmt.Fprintf(res, \"Hello(^-^)\/\\n%s\\n\",path)\n}\nfunc httpServer(gshCtx GshContext, argv []string){\n\thttp.HandleFunc(\"\/\", httpHandler)\n\taccport := \"localhost:9999\"\n\tfmt.Printf(\"--I-- HTTP Server Start at [%s]\\n\",accport)\n\thttp.ListenAndServe(accport,nil)\n}\nfunc xGo(gshCtx GshContext, argv[]string){\n\tgo gshellv(gshCtx,argv[1:]);\n}\nfunc xPs(gshCtx GshContext, argv[]string)(GshContext){\n\treturn gshCtx\n}\n\n\/\/ <a name=plugin>Plugin<\/a>\n\/\/ plugin [-ls [names]] to list plugins\n\/\/ Reference: <a href=https:\/\/golang.org\/src\/plugin\/>plugin<\/a> source code\nfunc whichPlugin(gshCtx GshContext,name string,argv[]string)(pi *PluginInfo){\n\tpi = nil\t\n\tfor _,p := range gshCtx.PluginFuncs {\n\t\tif p.Name == name && pi == nil {\n\t\t\tpi = &p\n\t\t}\n\t\tif !isin(\"-s\",argv){\n\t\t\t\/\/fmt.Printf(\"%v %v \",i,p)\n\t\t\tif isin(\"-ls\",argv){\n\t\t\t\tshowFileInfo(p.Path,argv)\n\t\t\t}else{\n\t\t\t\tfmt.Printf(\"%s\\n\",p.Name)\n\t\t\t}\n\t\t}\n\t}\n\treturn pi\n}\nfunc xPlugin(gshCtx GshContext, argv[]string)(GshContext,error){\n\tif len(argv) == 0 || argv[0] == \"-ls\" {\n\t\twhichPlugin(gshCtx,\"\",argv)\n\t\treturn gshCtx, nil\n\t}\n\tname := argv[0]\n\tPin := whichPlugin(gshCtx,name,[]string{\"-s\"})\n\tif Pin != nil {\n\t\tos.Args = argv \/\/ should be recovered?\n\t\tPin.Addr.(func())()\n\t\treturn gshCtx,nil\n\t}\n\tsofile := toFullpath(argv[0] + \".so\") \/\/ or find it by which($PATH)\n\n\tp, err := plugin.Open(sofile)\n\tif err != nil {\n\t\tfmt.Printf(\"--E-- plugin.Open(%s)(%v)\\n\",sofile,err)\n\t\treturn gshCtx, err\n\t}\n\tfname := \"Main\"\n\tf, err := p.Lookup(fname)\n\tif( err != nil ){\n\t\tfmt.Printf(\"--E-- plugin.Lookup(%s)(%v)\\n\",fname,err)\n\t\treturn gshCtx, err\n\t}\n\tpin := PluginInfo {p,f,name,sofile} \n\tgshCtx.PluginFuncs = append(gshCtx.PluginFuncs,pin)\n\tfmt.Printf(\"--I-- added (%d)\\n\",len(gshCtx.PluginFuncs))\n\n\t\/\/fmt.Printf(\"--I-- first call(%s:%s)%v\\n\",sofile,fname,argv)\n\tos.Args = argv\n\tf.(func())()\n\treturn gshCtx, err\n}\n\n\/\/ <a name=interpreter>Command Interpreter<\/a>\nfunc gshellv(gshCtx GshContext, argv []string) (_ GshContext, fin bool) {\n\tfin = false\n\n\tif gshCtx.CmdTrace { fmt.Fprintf(os.Stderr,\"--I-- gshellv((%d))\\n\",len(argv)) }\n\tif len(argv) <= 0 {\n\t\treturn gshCtx, false\n\t}\n\txargv := []string{}\n\tfor ai := 0; ai < len(argv); ai++ {\n\t\txargv = append(xargv,strsubst(&gshCtx,argv[ai],false))\n\t}\n\targv = xargv\n\tif false {\n\t\tfor ai := 0; ai < len(argv); ai++ {\n\t\t\tfmt.Printf(\"[%d] %s [%d]%T\\n\",\n\t\t\t\tai,argv[ai],len(argv[ai]),argv[ai])\n\t\t}\n\t}\n\tcmd := argv[0]\n\tif gshCtx.CmdTrace { fmt.Fprintf(os.Stderr,\"--I-- gshellv(%d)%v\\n\",len(argv),argv) }\n\tswitch { \/\/ https:\/\/tour.golang.org\/flowcontrol\/11\n\tcase cmd == \"\":\n\t\txPwd(gshCtx,[]string{}); \/\/ emtpy command\n\tcase cmd == \"-x\":\n\t\tgshCtx.CmdTrace = ! gshCtx.CmdTrace\n\tcase cmd == \"-ot\":\n\t\tsconnect(gshCtx, true, argv)\n\tcase cmd == \"-ou\":\n\t\tsconnect(gshCtx, false, argv)\n\tcase cmd == \"-it\":\n\t\tsaccept(gshCtx, true , argv)\n\tcase cmd == \"-iu\":\n\t\tsaccept(gshCtx, false, argv)\n\tcase cmd == \"-i\" || cmd == \"<\" || cmd == \"-o\" || cmd == \">\" || cmd == \"-a\" || cmd == \">>\" || cmd == \"-s\" || cmd == \"><\":\n\t\tredirect(gshCtx, argv)\n\tcase cmd == \"|\":\n\t\tgshCtx = fromPipe(gshCtx, argv)\n\tcase cmd == \"bg\" || cmd == \"-bg\":\n\t\trgshCtx, rfin := inBackground(gshCtx,argv[1:])\n\t\treturn rgshCtx, rfin\n\tcase cmd == \"call\":\n\t\tgshCtx, _ = excommand(gshCtx, false,argv[1:])\n\tcase cmd == \"cd\" || cmd == \"chdir\":\n\t\tgshCtx = xChdir(gshCtx,argv);\n\tcase cmd == \"close\":\n\t\tgshCtx = xClose(gshCtx,argv)\n\tcase cmd == \"#define\":\n\tcase cmd == \"echo\":\n\t\techo(argv,true)\n\tcase cmd == \"env\":\n\t\tenv(argv)\n\tcase cmd == \"eval\":\n\t\txEval(argv[1:],true)\n\tcase cmd == \"exec\":\n\t\tgshCtx, _ = excommand(gshCtx, true,argv[1:])\n\t\t\/\/ should not return here\n\tcase cmd == \"exit\" || cmd == \"quit\":\n\t\t\/\/ write Result code EXIT to 3>\n\t\treturn gshCtx, true\n\tcase cmd == \"-find\" || cmd == \"fin\" || cmd == \"ufind\" || cmd == \"uf\" || cmd == \"fu\":\n\t\tgshCtx = xFind(gshCtx,argv[1:])\n\tcase cmd == \"fork\":\n\t\t\/\/ mainly for a server\n\tcase cmd == \"-gen\":\n\t\tgen(gshCtx, argv)\n\tcase cmd == \"-go\":\n\t\txGo(gshCtx, argv)\n\tcase cmd == \"-grep\":\n\t\tgshCtx = xFind(gshCtx,argv)\n\tcase cmd == \"history\" || cmd == \"hi\": \/\/ hi should be alias\n\t\tgshCtx = xHistory(gshCtx, argv)\n\tcase cmd == \"jobs\":\n\t\txJobs(gshCtx,argv)\n\tcase cmd == \"-ls\":\n\t\tgshCtx = xFind(gshCtx,argv)\n\tcase cmd == \"nop\":\n\tcase cmd == \"pipe\":\n\t\tgshCtx = xOpen(gshCtx,argv)\n\tcase cmd == \"plug\" || cmd == \"plugin\" || cmd == \"pin\":\n\t\tgshCtx,_ = xPlugin(gshCtx,argv[1:])\n\tcase cmd == \"ps\":\n\t\txPs(gshCtx,argv)\n\tcase cmd == \"pstitle\": \/\/ to be gsh.title\n\tcase cmd == \"repeat\" || cmd == \"rep\": \/\/ repeat cond command\n\t\trepeat(gshCtx,argv)\n\tcase cmd == \"set\":\n\t\t\/\/ set name ...\n\tcase cmd == \"serv\":\n\t\thttpServer(gshCtx,argv)\n\tcase cmd == \"sleep\":\n\t\tsleep(gshCtx,argv)\n\tcase cmd == \"time\":\n\t\tgshCtx, fin = xTime(gshCtx,argv)\n\tcase cmd == \"pwd\":\n\t\txPwd(gshCtx,argv);\n\tcase cmd == \"ver\" || cmd == \"-ver\":\n\t\tfmt.Printf(\"%s\\n\",VERSION);\n\tcase cmd == \"where\":\n\t\t\/\/ data file or so?\n\tcase cmd == \"which\":\n\t\twhich(\"PATH\",argv);\n\tdefault:\n\t\tif whichPlugin(gshCtx,cmd,[]string{\"-s\"}) != nil {\n\t\t\tgshCtx, _ = xPlugin(gshCtx,argv)\n\t\t}else{\n\t\t\tgshCtx, _ = excommand(gshCtx,false,argv)\n\t\t}\n\t}\n\treturn gshCtx, fin\n}\n\nfunc gshelll(gshCtx GshContext, gline string) (gx GshContext, rfin bool) {\n\targv := strings.Split(string(gline),\" \")\n\tgshCtx, fin := gshellv(gshCtx,argv)\n\treturn gshCtx, fin\n}\nfunc tgshelll(gshCtx GshContext, gline string) (gx GshContext, xfin bool) {\n\tstart := time.Now()\n\tgshCtx, fin := gshelll(gshCtx,gline)\n\tend := time.Now()\n\telps := end.Sub(start);\n\tfmt.Printf(\"--I-- \" + time.Now().Format(time.Stamp) + \"(%d.%09ds)\\n\",\n\t\telps\/1000000000,elps%1000000000)\n\treturn gshCtx, fin\n}\nfunc Ttyid() (int) {\n\tfi, err := os.Stdin.Stat()\n\tif err != nil {\n\t\treturn 0;\n\t}\n\t\/\/fmt.Printf(\"Stdin: %v Dev=%d\\n\",\n\t\/\/\tfi.Mode(),fi.Mode()&os.ModeDevice)\n\tif (fi.Mode() & os.ModeDevice) != 0 {\n\t\tstat := syscall.Stat_t{};\n\t\terr := syscall.Fstat(0,&stat)\n\t\tif err != nil {\n\t\t\t\/\/fmt.Printf(\"--I-- Stdin: (%v)\\n\",err)\n\t\t}else{\n\t\t\t\/\/fmt.Printf(\"--I-- Stdin: rdev=%d %d\\n\",\n\t\t\t\/\/\tstat.Rdev&0xFF,stat.Rdev);\n\t\t\t\/\/fmt.Printf(\"--I-- Stdin: tty%d\\n\",stat.Rdev&0xFF);\n\t\t\treturn int(stat.Rdev & 0xFF)\n\t\t}\n\t}\n\treturn 0\n}\nfunc ttyfile(gshCtx GshContext) string {\n\t\/\/fmt.Printf(\"--I-- GSH_HOME=%s\\n\",gshCtx.GshHomeDir)\n\tttyfile := gshCtx.GshHomeDir + \"\/\" + \"gsh-tty\" +\n\t\t fmt.Sprintf(\"%02d\",gshCtx.TerminalId)\n\t\t \/\/strconv.Itoa(gshCtx.TerminalId)\n\t\/\/fmt.Printf(\"--I-- ttyfile=%s\\n\",ttyfile)\n\treturn ttyfile\n}\nfunc ttyline(gshCtx GshContext) (*os.File){\n\tfile, err := os.OpenFile(ttyfile(gshCtx),\n\t\tos.O_RDWR|os.O_CREATE|os.O_TRUNC,0600)\n\tif err != nil {\n\t\tfmt.Printf(\"--F-- cannot open %s (%s)\\n\",ttyfile(gshCtx),err)\n\t\treturn file;\n\t}\n\treturn file\n}\n\/\/ <a name=getline>Command Line Editor<\/a>\nfunc getline(gshCtx GshContext, hix int, skipping, with_exgetline bool, gsh_getlinev[]string, prevline string) (string) {\n\tif( skipping ){\n\t\treader := bufio.NewReaderSize(os.Stdin,LINESIZE)\n\t\tline, _, _ := reader.ReadLine()\n\t\treturn string(line)\n\t}else\n\tif( with_exgetline && gshCtx.GetLine != \"\" ){\n\t\t\/\/var xhix int64 = int64(hix); \/\/ cast\n\t\tnewenv := os.Environ()\n\t\tnewenv = append(newenv, \"GSH_LINENO=\"+strconv.FormatInt(int64(hix),10) )\n\n\t\ttty := ttyline(gshCtx)\n\t\ttty.WriteString(prevline)\n\t\tPa := os.ProcAttr {\n\t\t\t\"\", \/\/ start dir\n\t\t\tnewenv, \/\/os.Environ(),\n\t\t\t[]*os.File{os.Stdin,os.Stdout,os.Stderr,tty},\n\t\t\tnil,\n\t\t}\n\/\/fmt.Printf(\"--I-- getline=%s \/\/ %s\\n\",gsh_getlinev[0],gshCtx.GetLine)\nproc, err := os.StartProcess(gsh_getlinev[0],[]string{\"getline\",\"getline\"},&Pa)\n\t\tif err != nil {\n\t\t\tfmt.Printf(\"--F-- getline process error (%v)\\n\",err)\n\t\t\t\/\/ for ; ; { }\n\t\t\treturn \"exit (getline program failed)\"\n\t\t}\n\t\t\/\/stat, err := proc.Wait()\n\t\tproc.Wait()\n\t\tbuff := make([]byte,LINESIZE)\n\t\tcount, err := tty.Read(buff)\n\t\t\/\/_, err = tty.Read(buff)\n\t\t\/\/fmt.Printf(\"--D-- getline (%d)\\n\",count)\n\t\tif err != nil {\n\t\t\tif ! (count == 0) { \/\/ && err.String() == \"EOF\" ) {\n\t\t\t\tfmt.Printf(\"--E-- getline error (%s)\\n\",err)\n\t\t\t}\n\t\t}else{\n\t\t\t\/\/fmt.Printf(\"--I-- getline OK \\\"%s\\\"\\n\",buff)\n\t\t}\n\t\ttty.Close()\n\t\treturn string(buff[0:count])\n\t}else{\n\t\t\/\/ if isatty {\n\t\t\tfmt.Printf(\"!%d\",hix)\n\t\t\tfmt.Print(PROMPT)\n\t\t\/\/ }\n\t\treader := bufio.NewReaderSize(os.Stdin,LINESIZE)\n\t\tline, _, _ := reader.ReadLine()\n\t\treturn string(line)\n\t}\n}\n\/\/\n\/\/ $USERHOME\/.gsh\/\n\/\/\t\tgsh-rc.txt, or gsh-configure.txt\n\/\/              gsh-history.txt\n\/\/              gsh-aliases.txt \/\/ should be conditional?\n\/\/\nfunc gshSetupHomedir(gshCtx GshContext) (GshContext, bool) {\n\thomedir,found := userHomeDir()\n\tif !found {\n\t\tfmt.Printf(\"--E-- You have no UserHomeDir\\n\")\n\t\treturn gshCtx, true\n\t}\n\tgshhome := homedir + \"\/\" + GSH_HOME\n\t_, err2 := os.Stat(gshhome)\n\tif err2 != nil {\n\t\terr3 := os.Mkdir(gshhome,0700)\n\t\tif err3 != nil {\n\t\t\tfmt.Printf(\"--E-- Could not Create %s (%s)\\n\",\n\t\t\t\tgshhome,err3)\n\t\t\treturn gshCtx, true\n\t\t}\n\t\tfmt.Printf(\"--I-- Created %s\\n\",gshhome)\n\t}\n\tgshCtx.GshHomeDir = gshhome\n\treturn gshCtx, false\n}\nfunc setupGshContext()(GshContext,bool){\n\tgshPA := syscall.ProcAttr {\n\t\t\"\", \/\/ the staring directory\n\t\tos.Environ(), \/\/ environ[]\n\t\t[]uintptr{os.Stdin.Fd(),os.Stdout.Fd(),os.Stderr.Fd()},\n\t\tnil, \/\/ OS specific\n\t}\n\tcwd, _ := os.Getwd()\n\tgshCtx := GshContext {\n\t\tcwd, \/\/ StartDir\n\t\t\"\", \/\/ GetLine\n\t\t[]GChdirHistory { {cwd,time.Now()} }, \/\/ ChdirHistory\n\t\tgshPA,\n\t\t[]GCommandHistory{}, \/\/something for invokation?\n\t\tGCommandHistory{}, \/\/ CmdCurrent\n\t\tfalse,\n\t\t[]int{},\n\t\tsyscall.Rusage{},\n\t\t\"\", \/\/ GshHomeDir\n\t\tTtyid(),\n\t\tfalse,\n\t\t[]PluginInfo{},\n\t}\n\terr := false\n\tgshCtx, err = gshSetupHomedir(gshCtx)\n\treturn gshCtx, err\n}\n\/\/ <a name=main>Main loop<\/a>\nfunc script(gshCtxGiven *GshContext) (_ GshContext) {\n\tgshCtx,err0 := setupGshContext()\n\tif err0 {\n\t\treturn gshCtx;\n\t}\n\t\/\/fmt.Printf(\"--I-- GSH_HOME=%s\\n\",gshCtx.GshHomeDir)\n\t\/\/resmap()\n\tgsh_getlinev, with_exgetline :=\n\t\t which(\"PATH\",[]string{\"which\",\"gsh-getline\",\"-s\"})\n\tif with_exgetline {\n\t\tgsh_getlinev[0] = toFullpath(gsh_getlinev[0])\n\t\tgshCtx.GetLine = toFullpath(gsh_getlinev[0])\n\t}else{\n\tfmt.Printf(\"--W-- No gsh-getline found. Using internal getline.\\n\");\n\t}\n\n\tghist0 := gshCtx.CmdCurrent \/\/ something special, or gshrc script, or permanent history\n\tgshCtx.CommandHistory = append(gshCtx.CommandHistory,ghist0)\n\n\tprevline := \"\"\n\tskipping := false\n\tfor hix := len(gshCtx.CommandHistory); ; {\n\t\tgline := getline(gshCtx,hix,skipping,with_exgetline,gsh_getlinev,prevline)\n\t\tif skipping {\n\t\t\tif strings.Index(gline,\"fi\") == 0 {\n\t\t\t\tfmt.Printf(\"fi\\n\");\n\t\t\t\tskipping = false;\n\t\t\t}else{\n\t\t\t\t\/\/fmt.Printf(\"%s\\n\",gline);\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\t\tif strings.Index(gline,\"if\") == 0 {\n\t\t\t\/\/fmt.Printf(\"--D-- if start: %s\\n\",gline);\n\t\t\tskipping = true;\n\t\t\tcontinue\n\t\t}\n\t\tgline = strsubst(&gshCtx,gline,true)\n\t\t\/*\n\t\t\/\/ should be cared in substitution ?\n\t\tif 0 < len(gline) && gline[0] == '!' {\n\t\t\txgline, set, err := searchHistory(gshCtx,gline)\n\t\t\tif err {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif set {\n\t\t\t\t\/\/ set the line in command line editor\n\t\t\t}\n\t\t\tgline = xgline\n\t\t}\n\t\t*\/\n\t\tghist := gshCtx.CmdCurrent\n\t\tghist.WorkDir,_ = os.Getwd()\n\t\tghist.StartAt = time.Now()\n\t\trusagev1 := Getrusagev()\n\t\tgshCtx.CmdCurrent.FoundFile = []string{}\n\t\txgshCtx, fin := tgshelll(gshCtx,gline)\n\t\trusagev2 := Getrusagev()\n\t\tghist.Rusagev = RusageSubv(rusagev2,rusagev1)\n\t\tgshCtx = xgshCtx\n\t\tghist.EndAt = time.Now()\n\t\tghist.CmdLine = gline\n\t\tghist.FoundFile = gshCtx.CmdCurrent.FoundFile\n\n\t\t\/* record it but not show in list by default\n\t\tif len(gline) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tif gline == \"hi\" || gline == \"history\" { \/\/ don't record it\n\t\t\tcontinue\n\t\t}\n\t\t*\/\n\t\tgshCtx.CommandHistory = append(gshCtx.CommandHistory, ghist)\n\t\tif fin {\n\t\t\tbreak;\n\t\t}\n\t\tprevline = gline;\n\t\thix++;\n\t}\n\treturn gshCtx\n}\nfunc main() {\n\tscript(nil)\n\t\/\/gshCtx := script(nil)\n\t\/\/gshelll(gshCtx,\"time\")\n}\n\/\/<\/pre><\/details>\n\/\/<details id=todo><summary>Consideration<\/summary><pre>\n\/\/ - inter gsh communication, possibly running in remote hosts -- to be remote shell\n\/\/ - merged histories of multiple parallel gsh sessions\n\/\/ - alias as a function\n\/\/ - instant alias end environ export to the permanent > ~\/.gsh\/gsh-alias and gsh-environ\n\/\/ - retrieval PATH of files by its type\n\/\/ - gsh as an IME\n\/\/ - gsh a scheduler in precise time of within a millisecond\n\/\/ - all commands have its subucomand after \"---\" symbol\n\/\/ - filename expansion by \"-find\" command\n\/\/ - history of ext code and output of each commoand\n\/\/ - \"script\" output for each command by pty-tee or telnet-tee\n\/\/ - $BUILTIN command in PATH to show the priority\n\/\/ - \"?\" symbol in the command (not as in arguments) shows help request \n\/\/ - searching command with wild card like: which ssh-*\n\/\/ - longformat prompt after long idle time (should dismiss by BS)\n\/\/ - customizing by building plugin and dynamically linking it\n\/\/ - generating syntactic element like \"if\" by macro expansion (like CPP) >> alias\n\/\/ - \"!\" symbol should be used for negation, don't wast it just for job control\n\/\/ - don't put too long output to tty, record it into GSH_HOME\/session-id\/comand-id.log\n\/\/ - making canonical form of command at the start adding quatation or white spaces\n\/\/ - name(a,b,c) ... use \"(\" and \")\" to show both delimiter and realm\n\/\/ - name? or name! might be useful\n\/\/---END--- (^-^)\/ITS more<\/pre><\/details>\n\/*\n<details id=references><summary>References<\/summary><pre>\n<p>\n<a href=https:\/\/golang.org>The Go Programming Language<\/a>\n<iframe width=100% height=300 src=https:\/\/golang.org><\/iframe>\n\n<a href=https:\/\/developer.mozilla.org\/ja\/docs\/Web>MDN web docs<\/a>\n<a href=https:\/\/developer.mozilla.org\/ja\/docs\/Web\/HTML\/Element>HTML<\/a>,\nCSS, HTTP, JavaScript...\n<\/p>\n<\/pre><\/details>\n\n<img width=60px src=QR-ITS-more.jp.png>\n<style>\n #gsh{border-width:1;margin:0;padding:0;}\n #gsh{font-family:monospace,Courier New;color:#ddf;font-size:8px;}\n #gsh>header{height:100px;background-image:url(GShell-Logo00.png);}\n #gsh>header>div>note{color:#000;font-size:10pt;}\n #gsh>h2{color:#24a;font-family:Georgia;font-size:18pt;}\n #gsh>details{color:#888;background-color:#aaa;font-family:monospace}\n #gsh>details>summary{font-size:16pt;color:#24a;background-color:#eef;height:30px;}\n #gsh>details>pre{font-size:8pt;color:#223;background-color:#faffff;}\n #gsh>details>pre>a{color:#24a}\n<\/style>\n*\/ \/\/<\/span>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u5e83\u5831\uff1a\u305d\u308c\u3067\u3054\u4f9d\u983c\u306eGShell\u306e\u30ed\u30b4\u3067\u3059\u304c\u3001\u7b2c\u30bc\u30ed\u6b21\u6848\u3068\u3057\u3066\u3053\u306e\u3088\u3046\u306a\u3082\u306e\u3092\u8003\u3048\u3066\u307f\u307e\u3057\u305f\u3002 \u793e\u9577\uff1a\u3044\u3044\u611f\u3058\u3067\u3059\u304c\u3001S\u304c\u3082\u3046\u3061\u3087\u3068\u3075\u304f\u3088\u304b\u306a\u611f\u3058\u304c\u826f\u3044\u3067\u3059\u3002 \u5e83\u5831\uff1a\u305d\u308c\u304c\u306a\u304b\u306a\u304b\u3001\u305d\u306e\u3088\u3046\u306a\u30d5\u30a9\u30f3\u30c8\u304c\u306a\u3044\u3093\u3067\u3059\u3088\u306d\u2026\u3000 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/its-more.jp\/ja_jp\/?p=13994\" class=\"more-link\"><span class=\"screen-reader-text\">\"GShell 0.1.1 \u2212 \u30ed\u30b4\u6848\u3068CSS\u6574\u5099\" \u306e<\/span>\u7d9a\u304d\u3092\u8aad\u3080<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=\/wp\/v2\/posts\/13994"}],"collection":[{"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=13994"}],"version-history":[{"count":39,"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=\/wp\/v2\/posts\/13994\/revisions"}],"predecessor-version":[{"id":14430,"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=\/wp\/v2\/posts\/13994\/revisions\/14430"}],"wp:attachment":[{"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=13994"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=13994"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/its-more.jp\/ja_jp\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=13994"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}