Alex

有的故事值得一直说下去.
Home » Latest Posts

我们常用sudo,ssh、ftp命令操作服务器或者修改权限的时候都会要求输入password,但是shell脚本运行中该如何交互实现自动输入密码呢?

下面总结三种实现方法。

一、重定向: 用重定向方法实现交互的前提是指令需要有参数来指定密码输入方式,如ftp就有-i参数来指定使用标准输入来输入密码 shell用重定向作为标准输入的用法是:

ftp -i -n 192.168.15.16<<EOF user john pw@2018 ls EOF 二:管道: 跟重定向一样,指令同样要有参数来指定密码输入方式,如sudo的-S参数,passwd的-stdin参数,所以实现sudo自动输入密码的脚本如下:其中pw@2018为密码

echo 'pw@2018' | sudo -S cp fileone /tmp 实现自动修改密码的脚本写法如下:

echo 'password' | passwd -stdin username 三:expect: 上面介绍的两种方法前提条件是指令有参数来设定密码输入方式,像ssh指令就没有这样的参数,第三种交互方式就派上用场了,expect就是用来做交互用的,基本任何交互登录的场合都能使用,但是需要安装expect包。 CentOS下安装命令很简单:

sudo yum install expect Mac用户,可以通过homebrew安装(需要先安装homebrew)

brew install expect 测试脚本:实现rsync定时同步远程服务器文件 我们写一个简单的脚本,在脚本里配置密码,保存为scp.exp如下:

1,先写好rsync.ex脚本文件,在脚本里定义变量和保存密码

#!/usr/bin/expect set timeout 20

if { [llength $argv] < 2} { puts "Usage:" puts "$argv0 remote_path local_file" exit 1 }

set remote_path [lindex $argv 0] set local_file [lindex $argv 1] set passwd yourpassword

set passwderror 0

spawn rsync -avz --delete --exclude 'var' $remote_path $local_file

expect { "assword:" { if { $passwderror == 1 } { puts "passwd is error" exit 2 } set timeout 1000 set passwderror 1 send "$passwd\r" exp_continue } "es/no)?" { send "yes\r" exp_continue } timeout { puts "connect is timeout" exit 3 } } 脚本说明:

如果是sh脚本,第一行是#!/bin/bash,而这里是你机器上expect程序的路径,说明这段脚本是由expect来解释执行的 第一句是设定超时时间为20s set passwd yourpassword设置成你自己的密码 spawn是expect的语句,执行命令前都要加这句

2,把rsync.ex写到定时任务里

crontab -e 编辑如下,根据你自己的具体情况设置crontab参数和rsync.ex文件路径:

相关文章:CentOS等Linux服务器配置使用Rsync同步及Crontab定时任务

单独运行rsync.ex文件,如下:

expect /home/backup/rsync.ex [email protected]:/home/backup/* /local/backup/ 注意:expect跟bash类似,使用时要先登录到expect,所以首行要指定使用expect 在运行脚本时候要expect rsync.ex,不能sh rsync.ex了

1 假设我们需要开发的接口有这些 package main

import ( "net/http"

"github.com/gin-gonic/gin"

) func main() { r := gin.Default()

r.GET("/", func(c *gin.Context) {
	c.String(200, "首页")
})

r.GET("/news", func(c *gin.Context) {
	c.String(200, "新闻")
})

r.GET("/api", func(c *gin.Context) {
	c.String(200, "我是一个api接口")
})
r.GET("/api/userlist", func(c *gin.Context) {
	c.String(200, "我是一个api接口")
})
r.GET("/api/plist", func(c *gin.Context) {
	c.String(200, "我是一个api接口")
})
r.GET("/api/cart", func(c *gin.Context) {
	c.String(200, "我是一个api接口")
})

r.GET("/admin", func(c *gin.Context) {
	c.String(200, "后台首页")
})
r.GET("/admin/user", func(c *gin.Context) {
	c.String(200, "用户列表")
})
r.GET("/admin/user/add", func(c *gin.Context) {
	c.String(200, "增加用户")
})
r.GET("/admin/user/edit", func(c *gin.Context) {
	c.String(200, "修改用户")
})
r.GET("/admin/article", func(c *gin.Context) {
	c.String(200, "新闻列表")
})

r.Run(":8000")

}

/* 这样的路由对于开发人员来说维护起来是非常困难的 这时我们就需要使用到路由组 */ 2 使用Group分组 package main

import ( "net/http"

"github.com/gin-gonic/gin"

)

func main() { r := gin.Default()

defaultRouters := r.Group("/")
{
	defaultRouters.GET("/", func(c *gin.Context) {
		c.String(200, "首页")
	})

	defaultRouters.GET("/news", func(c *gin.Context) {
		c.String(200, "新闻")
	})
}

apiRouters := r.Group("/api")
{
	apiRouters.GET("/", func(c *gin.Context) {
		c.String(200, "我是一个api接口")
	})
	apiRouters.GET("/userlist", func(c *gin.Context) {
		c.String(200, "我是一个api接口userlist")
	})
	apiRouters.GET("/plist", func(c *gin.Context) {
		c.String(200, "我是一个api接口plist")
	})
	apiRouters.GET("/cart", func(c *gin.Context) {
		c.String(200, "我是一个api接口cart")
	})
}

adminRouters := r.Group("/admin")
{
	adminRouters.GET("/", func(c *gin.Context) {
		c.String(200, "后台首页")
	})
	adminRouters.GET("/user", func(c *gin.Context) {
		c.String(200, "用户列表")
	})
	adminRouters.GET("/user/add", func(c *gin.Context) {
		c.String(200, "增加用户")
	})
	adminRouters.GET("/user/edit", func(c *gin.Context) {
		c.String(200, "修改用户")
	})
	adminRouters.GET("/article", func(c *gin.Context) {
		c.String(200, "新闻列表")
	})
}

r.Run(":8000")

} 3 路由分离 首先我们创建一个routers文件夹,用于存放我们的路由,然后创建3个go文件按模块分别存储路由信息 pFFtBKs.png

接下来就开始分离路由,将相同模块的路由放一起,通过向函数中传递一个 r 的指针进行路由注册

adminRouters.go

package routers

import ( "github.com/gin-gonic/gin" )

func AdminRoutersInit(r *gin.Engine) { adminRouters := r.Group("/admin") { adminRouters.GET("/", func(c *gin.Context) { c.String(200, "后台首页") }) adminRouters.GET("/user", func(c *gin.Context) { c.String(200, "用户列表") }) adminRouters.GET("/user/add", func(c *gin.Context) { c.String(200, "增加用户") }) adminRouters.GET("/user/edit", func(c *gin.Context) { c.String(200, "修改用户") }) adminRouters.GET("/article", func(c *gin.Context) { c.String(200, "新闻列表") }) } } apiRouters.go

package routers

import "github.com/gin-gonic/gin"

func ApiRoutersInit(r *gin.Engine) { apiRouters := r.Group("/api") { apiRouters.GET("/", func(c *gin.Context) { c.String(200, "我是一个api接口") }) apiRouters.GET("/userlist", func(c *gin.Context) { c.String(200, "我是一个api接口userlist") }) apiRouters.GET("/plist", func(c *gin.Context) { c.String(200, "我是一个api接口plist") }) apiRouters.GET("/cart", func(c *gin.Context) { c.String(200, "我是一个api接口cart") }) } } defaultRouters.go

package routers

import "github.com/gin-gonic/gin"

func DefaultRoutersInit(r *gin.Engine) { defaultRouters := r.Group("/") { defaultRouters.GET("/", func(c *gin.Context) { c.String(200, "首页") })

	defaultRouters.GET("/news", func(c *gin.Context) {
		c.String(200, "新闻")
	})
}

} main.go

package main

import ( "awesomeProject/gin/routers" "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() routers.AdminRoutersInit(r) routers.ApiRoutersInit(r) routers.DefaultRoutersInit(r) r.Run(":8000") } 4 小结 /* 目前我们已经可以将路由根据模块功能进行划分出来,区分开,方便后期的维护管理 但是我们只想要路由文件中只有路由的配置,不想要业务逻辑的实现,那我们还得将路由和业务逻辑进行拆分 需要将func单独写到一个文件下面方便管理,这些内容下一篇文章将进行解决

如果熟悉 python 的 Django的话应该是非常容易理解的

*/

Gin控制器分离 1 函数式 /* apiRouters.GET("/", func(c *gin.Context) { c.String(200, "我是一个api接口") }) 这样的一个路由注册我们发现,后面都跟了一个匿名函数,那我们将这个匿名函数全部取出来放在一个固定的地方就可以实现路由和业务逻辑的分离了 */ 1.1 将adminRouters.go中的业务逻辑全部取出 创建一个controllers文件夹,按照模块创建相应的文件夹以及文件,这些文件我们就用来存储相应的业务逻辑

pFFUEtK.png

admin.go 还需要加上函数名

package admin

import ( "github.com/gin-gonic/gin" )

func AdminIndex(c *gin.Context) { c.String(200, "后台首页") }

func AdminUser(c *gin.Context) { c.String(200, "用户列表") }

func AdminUserAdd(c *gin.Context) { c.String(200, "增加用户") }

func AdminUserEdit(c *gin.Context) { c.String(200, "修改用户") }

func AdminNews(c gin.Context) { c.String(200, "新闻列表") } / 将业务逻辑全部写在一起方便管理 */ adminRouter.go

/* 回到路由配置中 */

package routers

import ( "github.com/gin-gonic/gin"

"awesomeProject/gin/controllers/admin"

)

func AdminRoutersInit(r *gin.Engine) { adminRouters := r.Group("/admin") { adminRouters.GET("/", admin.AdminIndex) adminRouters.GET("/user", admin.AdminUser) adminRouters.GET("/user/add", admin.AdminUserAdd) adminRouters.GET("/user/edit", admin.AdminUserEdit) adminRouters.GET("/article", admin.AdminNews) } }

/* 不需要加() 加()了的话就变成了执行函数了 */ 2 结构体式 做法很简单,我们只需要将具体的业务逻辑写在结构体中就行了

api.go

package api

import "github.com/gin-gonic/gin"

type ApiController struct{}

func (con ApiController) Api(c *gin.Context) { c.String(200, "我是一个api接口") }

func (con ApiController) ApiUserList(c *gin.Context) { c.String(200, "我是一个api接口userlist") }

func (con ApiController) ApiPlist(c *gin.Context) { c.String(200, "我是一个api接口plist") }

func (con ApiController) ApiCart(c *gin.Context) { c.String(200, "我是一个api接口cart") } apiRouters.go

package routers

import ( "awesomeProject/gin/controllers/api" "github.com/gin-gonic/gin" )

func ApiRoutersInit(r *gin.Engine) { apiRouters := r.Group("/api") { apiRouters.GET("/", api.ApiController{}.Api) apiRouters.GET("/userlist", api.ApiController{}.ApiUserList) apiRouters.GET("/plist", api.ApiController{}.ApiPlist) apiRouters.GET("/cart", api.ApiController{}.ApiCart) } }

即使把微屁恩开启全局模式,在Android Studio下仍然提示Download Gradle失败,或者下载速度非常非常慢。

这时候可以点击下载进度条,在弹出Build之类的窗口可以看到下载链接,类似于https://services.gradle.org/distributions/gradle-8.2-all.zip,我们复制这个链接到迅雷或者浏览器,可以快速下载下来。

然后得到这个压缩包,用everything搜索gradle关键词,可以在电脑找到类似于:

C:\Users\Administrator.gradle\wrapper\dists\gradle-8.2-bin\bbg7u40eoinfdyxsxr3z4i7ta

的临时目录,把压缩包复制到这个目录。

重启Android Studio,等待它自动配置完成。 作者:bcbooo https://www.bilibili.com/read/cv31740586/ 出处:bilibili

How to implement the Sylius theme? Practical tips and examples

Natively in Sylius, you can customize your storefront design in many ways. This article focuses on themes that are used to manage the appearance of each channel. Let’s say you are creating a store that will have more than one sales channel and you would like each channel to look differently. In this example, I’ll show you how to create a custom theme and then use it in a channel.

How to create your own theme?

The theme functionality is in a separate Sylius Theme Bundle repository, so you can install it in another project as well (but in the docs you will find more information about it). The Sylius Standard Edition has a theme bundle installed already. The first step you need to take is to enable themes in your project.

Find this file in your project (if it does not exist create it):

config/packages/sylius_theme.yaml

And then add the following lines.

sylius_theme:
    sources:
        filesystem:
            directories:
                 - "%kernel.project_dir%/themes"

Next, create a new directory tree in the themes directory:

themes/BlueTheme

then create a “composer.json” file in a new theme folder:

themes/BlueTheme/composer.json

with the following code

{
    "name": "bitbag/blue-theme",
    "authors": [
        {
            "name": "Dan Smith",
            "email": "[email protected]"
        }
    ],
    "extra": {
        "sylius-theme": {
            "title": "Blue Theme"
        }
    }
}

To install a created theme you need to run both of the following commands:

bin/console assets:install 
bin/console sylius:theme:assets:install

Do you want us to help you with Sylius themes?

imgSpider 采集中...

How to overwrite a template only in one of the themes?

Let’s say that in the shopping cart view in one of the channels the “You may also like” section should not be displayed, additionally we want to add labels to the product prices in the shopping cart table.

The only thing left is to create custom HTML files in the “BlueTheme” folder. We need to find the template files that we want to overwrite. In our case:

vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/views/Cart/Summary/_item.html.twig

Copy the content of this file and paste it into the location:

themes/BlueTheme/templates/bundles/SyliusShopBundle/Cart/Summary/_item.html.twig

With the following code:

{% import "@SyliusShop/Common/Macro/money.html.twig" as money %}

{% set product_variant = item.variant %}

<tr {{ sylius_test_html_attribute('cart-product-row', item.productName) }}>
    <td class="single line" {{ sylius_test_html_attribute('cart-item', loop_index|default(null) ) }}>
        {% include '@SyliusShop/Product/_info.html.twig' with {'variant': product_variant} %}
    </td>
    <td class="right aligned">
        {% if item.unitPrice != item.discountedUnitPrice %}
            <span class="sylius-regular-unit-price" {{ sylius_test_html_attribute('cart-product-regular-unit-price') }}>
                <div class="ui red horizontal label">
                    <span class="old-price">{{ money.convertAndFormat(item.unitPrice) }}</span>
                </div>
            </span>
        {% endif %}
        <div class="ui red horizontal label">
            <span class="sylius-unit-price" {{ sylius_test_html_attribute('cart-product-unit-price', item.productName) }}>{{ money.convertAndFormat(item.discountedUnitPrice) }}</span>
        </div>
    </td>
    <td class="center aligned">
        <span class="sylius-quantity ui form">{{ form_widget(form.quantity, sylius_test_form_attribute('cart-item-quantity-input', item.productName)|sylius_merge_recursive({'attr': {'form': main_form}})) }}</span>
    </td>
    <td class="center aligned">
        <form action="{{ path('sylius_shop_cart_item_remove', {'id': item.id}) }}" method="post">
            <input type="hidden" name="_method" value="DELETE" />
            <input type="hidden" name="_csrf_token" value="{{ csrf_token(item.id) }}" />
            <button type="submit" class="ui circular icon button sylius-cart-remove-button" {{ sylius_test_html_attribute('cart-remove-button', item.productName) }} ><i class="remove icon"></i></button>
        </form>
    </td>
    <td class="right aligned">
        <div class="ui red horizontal label">
            <span class="sylius-total" {{ sylius_test_html_attribute('cart-product-subtotal') }}>{{ money.convertAndFormat(item.subtotal) }}</span>
        </div>
    </td>
</tr>

The second template is:

vendor/sylius/sylius/src/Sylius/Bundle/ShopBundle/Resources/views/Cart/Summary/_suggestions.html.twig

Simply paste an empty file:

themes/BlueTheme/templates/bundles/SyliusShopBundle/Cart/Summary/_suggestions.html.twig

How to use a custom theme?

Now you can use this layout in the admin panel channel configuration.

Create new or edit Channel: go to Admin panel -> Channel -> [Create/Edit] and select “Blue Theme” in “Look & feel -> Theme”

imgSpider 采集中...

After implementing these changes you should see different cart views in the channel for which the “Blue theme” template has been chosen. if you don’t see any change after page refreshing, try clearing cache by Symfony command:

bin/console cache:clear 

Finally, you should see:

imgSpider 采集中...

Remember that you can always simply override a template instead of implementing a new theme.

See the Sylius documentation for more information on the Sylius theme and Sylius templates. If you have any doubts, feel free to contact us.

Life is fantastic
🥕 More