JSch:Java Secure Channel -- java 代碼實現 ssh 遠程操作

前些天發現了一個巨牛的人工智能學習網站,通俗易懂,風趣幽默,忍不住分享一下給大家。點擊跳轉到教程。

JSch 是SSH2的一個純Java實現。

它允許你連接到一個 sshd 服務器,使用端口轉發,X11轉發,文件傳輸等等。

你可以將它的功能集成到你自己的程序中。

同時該項目也提供一個J2ME版本用來在手機上直連SSHD服務器。

?

?

官網:http://www.jcraft.com/jsch/中有很多例子http://www.jcraft.com/jsch/examples/

這里先采用(已做修改)其中2個來進行簡單論述,希望對大家有所幫助。

本文采用的jsch版本是0.1.51.?

下載地址:http://sourceforge.net/projects/jsch/files/jsch/0.1.54/jsch-0.1.54.zip/download。

本文采用的Linux操作系統是CentOS6.5.

TIPS: 查看Linux操作系統(內核)版本可以使用:uname -a; uname -r; cat /etc/issue; cat /etc/redhat-release等命令。

?

?

第一個例子:采用Java模擬shell操作。
這里涉及到幾個參數,會在下面的代碼中有所體現:

  • USER:所連接的Linux主機登錄時的用戶名
  • PASSWORD:登錄密碼
  • HOST:主機地址
  • DEFAULT_SSH_PROT=端口號,默認為22
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.test.jsch;
/**
?* This program enables you to connect to sshd server and get the shell prompt.
?* You will be asked username, hostname and passwd.
?* If everything works fine, you will get the shell prompt. Output may
?* be ugly because of lacks of terminal-emulation, but you can issue commands.
?*/
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import com.jcraft.jsch.Channel;
public class Shell{
????private static final String USER="root";
????private static final String PASSWORD="********";
????private static final String HOST="localhost";
????private static final int DEFAULT_SSH_PORT=22;
????public static void main(String[] arg){
????????try{
????????????JSch jsch=new JSch();
????????????Session session = jsch.getSession(USER,HOST,DEFAULT_SSH_PORT);
????????????session.setPassword(PASSWORD);
????????????UserInfo userInfo = new UserInfo() {
????????????????@Override
????????????????public String getPassphrase() {
????????????????????System.out.println("getPassphrase");
????????????????????return null;
????????????????}
????????????????@Override
????????????????public String getPassword() {
????????????????????System.out.println("getPassword");
????????????????????return null;
????????????????}
????????????????@Override
????????????????public boolean promptPassword(String s) {
????????????????????System.out.println("promptPassword:"+s);
????????????????????return false;
????????????????}
????????????????@Override
????????????????public boolean promptPassphrase(String s) {
????????????????????System.out.println("promptPassphrase:"+s);
????????????????????return false;
????????????????}
????????????????@Override
????????????????public boolean promptYesNo(String s) {
????????????????????System.out.println("promptYesNo:"+s);
????????????????????return true;//notice here!
????????????????}
????????????????@Override
????????????????public void showMessage(String s) {
????????????????????System.out.println("showMessage:"+s);
????????????????}
????????????};
????????????session.setUserInfo(userInfo);
????????????// It must not be recommended, but if you want to skip host-key check,
????????????// invoke following,
????????????// session.setConfig("StrictHostKeyChecking", "no");
????????????//session.connect();
????????????session.connect(30000);?? // making a connection with timeout.
????????????Channel channel=session.openChannel("shell");
????????????// Enable agent-forwarding.
????????????//((ChannelShell)channel).setAgentForwarding(true);
????????????channel.setInputStream(System.in);
??????/*
??????// a hack for MS-DOS prompt on Windows.
??????channel.setInputStream(new FilterInputStream(System.in){
??????????public int read(byte[] b, int off, int len)throws IOException{
????????????return in.read(b, off, (len>1024?1024:len));
??????????}
????????});
???????*/
????????????channel.setOutputStream(System.out);
??????/*
??????// Choose the pty-type "vt102".
??????((ChannelShell)channel).setPtyType("vt102");
??????*/
??????/*
??????// Set environment variable "LANG" as "ja_JP.eucJP".
??????((ChannelShell)channel).setEnv("LANG", "ja_JP.eucJP");
??????*/
????????????//channel.connect();
????????????channel.connect(3*1000);
????????}
????????catch(Exception e){
????????????System.out.println(e);
????????}
????}
}

運行結果:

1
2
3
4
5
6
promptYesNo:
The authenticity of host '10.101.139.5' can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to continue connecting?
trueLast login: Thu Sep 29 18:40:56 2016 from 10.101.48.240
[root@hidden ~]#

輸入ls查看:

1
2
3
4
5
6
7
(省略一些....)
[root@hidden ~]# ls
ls
1.txt??????????? install.log.syslog? vmware-tools-distrib? 模板? 文檔? 桌面
anaconda-ks.cfg? logs??????????????? workspace???????????? 視頻? 下載
install.log????? util??????????????? 公共的??????????????? 圖片? 音樂
[root@hidden ~]#

這樣就和在原linux系統中一樣使用shell功能了。

如果需要跳過如下的檢測:

1
2
3
The authenticity of host '10.101.139.5' can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to continue connecting?

只需要在程序中加入相應的代碼:

1
session.setConfig("StrictHostKeyChecking", "no");

運行結果:

1
2
Last login: Thu Sep 29 18:39:18 2016 from 10.101.48.240
[root@hidden ~]#

第二個例子:運行一條shell指令,這里就那“ls”做例子好了。

No more talk, show you the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.test.jsch;
import com.jcraft.jsch.*;
import java.io.*;
public class Exec{
????private static final String USER="root";
????private static final String PASSWORD="********";
????private static final String HOST="localhost";
????private static final int DEFAULT_SSH_PORT=22;
????public static void main(String[] arg){
????????try{
????????????JSch jsch=new JSch();
????????????Session session = jsch.getSession(USER,HOST,DEFAULT_SSH_PORT);
????????????session.setPassword(PASSWORD);
????????????// username and password will be given via UserInfo interface.
????????????session.setUserInfo(new MyUserInfo());
????????????session.connect();
????????????String command="ls";
????????????Channel channel=session.openChannel("exec");
????????????((ChannelExec)channel).setCommand(command);
????????????// X Forwarding
????????????// channel.setXForwarding(true);
????????????//channel.setInputStream(System.in);
????????????channel.setInputStream(null);
????????????//channel.setOutputStream(System.out);
????????????//FileOutputStream fos=new FileOutputStream("/tmp/stderr");
????????????//((ChannelExec)channel).setErrStream(fos);
????????????((ChannelExec)channel).setErrStream(System.err);
????????????InputStream in=channel.getInputStream();
????????????channel.connect();
????????????byte[] tmp=new byte[1024];
????????????while(true){
????????????????while(in.available()>0){
????????????????????int i=in.read(tmp, 0, 1024);
????????????????????if(i<0)break;
????????????????????System.out.print(new String(tmp, 0, i));
????????????????}
????????????????if(channel.isClosed()){
????????????????????if(in.available()>0) continue;
????????????????????System.out.println("exit-status: "+channel.getExitStatus());
????????????????????break;
????????????????}
????????????????try{Thread.sleep(1000);}catch(Exception ee){}
????????????}
????????????channel.disconnect();
????????????session.disconnect();
????????}
????????catch(Exception e){
????????????System.out.println(e);
????????}
????}
????private static class MyUserInfo implements UserInfo{
????????@Override
????????public String getPassphrase() {
????????????System.out.println("getPassphrase");
????????????return null;
????????}
????????@Override
????????public String getPassword() {
????????????System.out.println("getPassword");
????????????return null;
????????}
????????@Override
????????public boolean promptPassword(String s) {
????????????System.out.println("promptPassword:"+s);
????????????return false;
????????}
????????@Override
????????public boolean promptPassphrase(String s) {
????????????System.out.println("promptPassphrase:"+s);
????????????return false;
????????}
????????@Override
????????public boolean promptYesNo(String s) {
????????????System.out.println("promptYesNo:"+s);
????????????return true;//notice here!
????????}
????????@Override
????????public void showMessage(String s) {
????????????System.out.println("showMessage:"+s);
????????}
????}
}

運行結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
promptYesNo:The authenticity of host '10.101.139.5' can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to continue connecting?
1.txt
anaconda-ks.cfg
install.log
install.log.syslog
logs
util
vmware-tools-distrib
workspace
公共的
模板
視頻
圖片
文檔
下載
音樂
桌面
exit-status: 0

第二個例子相比于第一個例子來說將UserInfo采用static class的方式提取出來,這樣更直觀一點。

JSch是以多線程方式一下,所以代碼在connect后如果不disconnect channel和session,以及相關stream, 程序會一直等待,直到關閉。

需要注意的一個問題,相關的Stream和Channel是一定要關閉的,那么應該在什么時候來關?執行connect后,JSch接受客戶端結果需要一定的時間(以秒計),如果馬上關閉session就會發現什么都沒接受到或內容不全。

還有一點注意,使用shell時,看到執行后沒有結果,解決辦法是在命令行后加上”\n”字符,server端就認為是一條完整的命令了。

最后將第一個和第二個例子合并,并提取一些公用模塊,以便更好的理解和使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package com.test.jsch;
import com.jcraft.jsch.*;
import java.io.*;
import java.util.concurrent.TimeUnit;
import static java.lang.String.format;
/**
?* Created by hidden on 2016/9/29.
?*/
public class SSHExecutor {
????private static long INTERVAL = 100L;
????private static int SESSION_TIMEOUT = 30000;
????private static int CHANNEL_TIMEOUT = 3000;
????private JSch jsch = null;
????private Session session = null;
????private SSHExecutor(SSHInfo sshInfo) throws JSchException {
????????jsch =new JSch();
????????session = jsch.getSession(sshInfo.getUser(),sshInfo.getHost(),sshInfo.getPort());
????????session.setPassword(sshInfo.getPassword());
????????session.setUserInfo(new MyUserInfo());
????????session.connect(SESSION_TIMEOUT);
????}
????/*
????* 在這里修改訪問入口,當然可以把這個方法弄到SSHExecutor外面,這里是方便操作才這么做的
????* */
????public static SSHExecutor newInstance() throws JSchException {
????????SSHInfo sshInfo = new SSHInfo("root","******","locahost",22);
????????return new SSHExecutor(sshInfo);
????}
????/*
????* 注意編碼轉換
????* */
????public long shell(String cmd, String outputFileName) throws JSchException, IOException, InterruptedException {
????????long start = System.currentTimeMillis();
????????Channel channel = session.openChannel("shell");
????????PipedInputStream pipeIn = new PipedInputStream();
????????PipedOutputStream pipeOut = new PipedOutputStream( pipeIn );
????????FileOutputStream fileOut = new FileOutputStream( outputFileName, true);
????????channel.setInputStream(pipeIn);
????????channel.setOutputStream(fileOut);
????????channel.connect(CHANNEL_TIMEOUT);
????????pipeOut.write(cmd.getBytes());
????????Thread.sleep( INTERVAL );
????????pipeOut.close();
????????pipeIn.close();
????????fileOut.close();
????????channel.disconnect();
????????return System.currentTimeMillis() - start;
????}
????public int exec(String cmd) throws IOException, JSchException, InterruptedException {
????????ChannelExec channelExec = (ChannelExec)session.openChannel( "exec" );
????????channelExec.setCommand( cmd );
????????channelExec.setInputStream( null );
????????channelExec.setErrStream( System.err );
????????InputStream in = channelExec.getInputStream();
????????channelExec.connect();
????????int res = -1;
????????StringBuffer buf = new StringBuffer( 1024 );
????????byte[] tmp = new byte[ 1024 ];
????????while ( true ) {
????????????while ( in.available() > 0 ) {
????????????????int i = in.read( tmp, 0, 1024 );
????????????????if ( i < 0 ) break;
????????????????buf.append( new String( tmp, 0, i ) );
????????????}
????????????if ( channelExec.isClosed() ) {
????????????????res = channelExec.getExitStatus();
????????????????System.out.println( format( "Exit-status: %d", res ) );
????????????????break;
????????????}
????????????TimeUnit.MILLISECONDS.sleep(100);
????????}
????????System.out.println( buf.toString() );
????????channelExec.disconnect();
????????return res;
????}
????public Session getSession(){
????????return session;
????}
????public void close(){
????????getSession().disconnect();
????}
????/*
????* SSH連接信息
????* */
????public static class SSHInfo{
????????private String user;
????????private String password;
????????private String host;
????????private int port;
????????public SSHInfo(String user, String password, String host, int port) {
????????????this.user = user;
????????????this.password = password;
????????????this.host = host;
????????????this.port = port;
????????}
????????public String getUser() {
????????????return user;
????????}
????????public String getPassword() {
????????????return password;
????????}
????????public String getHost() {
????????????return host;
????????}
????????public int getPort() {
????????????return port;
????????}
????}
????/*
????* 自定義UserInfo
????* */
????private static class MyUserInfo implements UserInfo{
????????@Override public String getPassphrase() { return null; }
????????@Override public String getPassword() { return null; }
????????@Override public boolean promptPassword(String s) { return false; }
????????@Override public boolean promptPassphrase(String s) { return false; }
????????@Override
????????public boolean promptYesNo(String s) {
????????????System.out.println(s);
????????????System.out.println("true");
????????????return true;
????????}
????????@Override public void showMessage(String s) { }
????}
}

測試代碼:

1
2
3
4
5
6
7
8
9
SSHExecutor ssh =? SSHExecutor.newInstance();
System.out.println("================");
long shell1 = ssh.shell("ls\n","C:\\Users\\hidden\\Desktop\\shell.txt");
long shell2 = ssh.shell("pwd\n","C:\\Users\\hidden\\Desktop\\shell.txt");
System.out.println("shell 1 執行了"+shell1+"ms");
System.out.println("shell 2 執行了"+shell2+"ms");
System.out.println("================");
int cmd1 = ssh.exec("ls\n");
ssh.close();

測試結果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
The authenticity of host '10.101.139.5' can't be established.
RSA key fingerprint is 59:0f:32:fc:7b:54:3d:90:c0:ef:5a:6b:fb:11:55:e1.
Are you sure you want to continue connecting?
true
================
shell 1 執行了142ms
shell 2 執行了132ms
================
Exit-status: 0
1.txt
anaconda-ks.cfg
install.log
install.log.syslog
logs
util
vmware-tools-distrib
workspace
公共的
模板
視頻
圖片
文檔
下載
音樂
桌面

還有解釋查看一下左邊是否有個shell.txt以及shell.txt是否有相應的內容。

?

?

轉自:http://www.importnew.com/22322.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/449341.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/449341.shtml
英文地址,請注明出處:http://en.pswp.cn/news/449341.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

國信證券學習系列(3)

日內回轉策略&#xff1a;做T策略 擇時交易&#xff1a; if date[-8:-3] ! 14:55:if macd > 0 and macd_pre < 0:# 根據MACD>0則開倉,小于0則平倉if avaliable > df.iloc[-1, 0] * ContextInfo.Lots * 100:order_shares(ContextInfo.get_universe()[0], ContextIn…

時序數據庫連載系列: 時序數據庫一哥InfluxDB之存儲機制解析

2019獨角獸企業重金招聘Python工程師標準>>> InfluxDB 的存儲機制解析 本文介紹了InfluxDB對于時序數據的存儲/索引的設計。由于InfluxDB的集群版已在0.12版就不再開源&#xff0c;因此如無特殊說明&#xff0c;本文的介紹對象都是指 InfluxDB 單機版 1. InfluxDB 的…

如何在Linux上提高文本的搜索效率

本文由 極客范 - minejo 翻譯自 Xmodulo。歡迎加入極客翻譯小組&#xff0c;同我們一道翻譯與分享。轉載請參見文章末尾處的要求。對于系統管理員或程序員來說&#xff0c;當需要在復雜配置的目錄中或者在大型源碼樹中搜尋特定的文本或模式時&#xff0c;grep類型的工具大概是…

Spring Boot 10:處理Json數據中的null值

Jackson版&#xff1a; /*** Jackson 配置類 對Json數據進行特殊處理** Author YangXuyue* Date 2019/04/02 07:12*/ Configuration public class JacksonConfig {/*** 配置Jackson** param builder* return* Author YangXuyue* Date 2019/04/02 07:14*/BeanPrimaryConditional…

國信證券學習系列(4)

機器學習篇章&#xff0c;本章不過時腳本小子&#xff0c;機器學習最核心的是機器&#xff0c;是模型。 學習&#xff0c;無非就是找些有的沒的因子扔進去&#xff0c;但說實話&#xff0c;機器學習&#xff0c;太過容易過擬合&#xff0c;容易無效化。回測好看的一筆&#xf…

JSch - Java Secure Channel : java 代碼實現服務器遠程操作

一、前言 前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 JSch是SSH2的純Java實現 。 JSch允許您連接到sshd服務器并使用端口轉發&#xff0c;X11轉發&#xff0c;文件傳輸等&#xff0…

前嗅ForeSpider教程:數據建表

今天&#xff0c;小編為大家帶來的教程是&#xff1a;如何在前嗅ForeSpider中&#xff0c;進行數據建表操作及各注意事項。主要內容包括&#xff1a;快速建表&#xff0c;自由建表&#xff0c;字段參數&#xff0c;數據表的創建&#xff0c;關聯與刪除&#xff0c;以及表單變更…

世紀大爭論:Linux還是GNU/Linux?

本文由 極客范 - 愛開源的貢獻開源社區 翻譯自 Chris Hoffman。歡迎加入極客翻譯小組&#xff0c;同我們一道翻譯與分享。轉載請參見文章末尾處的要求。我們在網上已經習慣用“Linux”來稱呼Linux操作系統了&#xff0c;然而&#xff0c;偶爾也用“GNU/Linux”來稱呼和指代同…

PyTorch Softmax

PyTorch provides 2 kinds of Softmax class. The one is applying softmax along a certain dimension. The other is do softmax on a spatial matrix sized in B, C, H, W. But it seems like some problems existing in Softmax2d. : ( 轉載于:https://www.cnblogs.com/hiz…

國信證券學習系列(5)

網格策略&#xff0c;號稱勝率100%的策略&#xff0c;只要扛得住回撤&#xff0c;怎么說呢&#xff0c;它包含了最簡單的思想&#xff0c;大道至簡&#xff0c;真的是沒有什么復雜的&#xff0c;原理清晰&#xff0c;思路簡單。可以明確知道我掙的是那筆錢&#xff0c;為什么獲…

promise

## 前言 今天來分享下promise的用法&#xff0c;es6偉大發明之一&#xff0c;當初我學習的時候也是蠻頭大的&#xff0c;不知道為啥&#xff0c;整個腦子就是&#xff0c;我在哪&#xff0c;我要干啥的懵圈&#xff0c;后面認真學習之后&#xff0c;覺得真是十分好用&#xff0…

計算機集群 解說

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 計算機集群簡稱集群是一種計算機系統&#xff0c;它通過一組松散集成的計算機軟件和/或硬件連接起來高度緊密地協作完成計算工作。 在某…

同時尋找最大數和最小數的最優算法 第二大數

我們知道&#xff0c;在一個容量為n的數據集合中尋找一個最大數&#xff0c;不管用什么樣的比較算法&#xff0c;至少要比較n-1次&#xff0c;就算是用競標賽排序也得比較n-1次&#xff0c;否則你找到的就不能保證是最大的數。那么&#xff0c;在一個容量為n的數據集合中同時尋…

淺談mpvue項目目錄和文件結構

2019獨角獸企業重金招聘Python工程師標準>>> 在Visual Studio Code里面打開項目文件夾&#xff0c;我們可以看到類似如下的文件結構&#xff1a; 1、package.json文件 package.json是項目的主配置文件&#xff0c;里面包含了mpvue項目的基本描述信息、項目所依賴的各…

[AHOI2009]最小割(最大流+tarjan)

繼續填坑了&#xff0c;啦啦啦 這道題本來是準備枚舉每個邊&#xff0c;暫時去除它&#xff0c;但發現時間會爆炸的 于是決定另辟蹊徑 于是這篇題解就應運而生 首先還是網絡流跑一邊 畢竟題目叫最小割嘛&#xff0c;給個面子 然后跑一邊tarjan對滿流的邊處理掉&#xff0c;即不…

進程間通信---信號

什么是信號&#xff1f; 】 信號處理流程 信號類型 發送信號的函數 參數sig&#xff1a;代表 信號 接收信號的函數 參數 handle 的處理方式有幾種&#xff1f; 實例代碼 實例邏輯 圖中的等待操作使用&#xff1a;pause&#xff08;&#xff09;函數 代碼 在這里插入代碼片…

大白話解說,半分鐘就懂 --- 分布式與集群是什么 ? 區別是什么?

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 PS&#xff1a;這篇文章算是筆記&#xff0c;僅部分文字是原創&#xff0c;相當內容只是收集、整理、提煉、總結別人寫的。 沒有標為原創…

國信證券學習系列(6)

行業輪動策略&#xff1a; 本策略每隔1個月定時觸發計算1000能源&#xff08;399381.SZ&#xff09;、1000材料&#xff08;399382.SZ&#xff09;、1000工業&#xff08;399383.SZ&#xff09;、1000可選&#xff08;399384.SZ&#xff09;、1000消費&#xff08;399385.SZ&a…

用Linux命令行修圖——縮放、編輯、轉換格式——一切皆有可能

本文由 極客范 - 八卦愛好者 翻譯自 How-To Geek。歡迎加入極客翻譯小組&#xff0c;同我們一道翻譯與分享。轉載請參見文章末尾處的要求。ImageMagick是一系列的用于修改、加工圖像的命令行工具。ImageMagick能夠快速地使用命令行對圖片進行操作&#xff0c;對大量的圖片進行…

劍指offer:二維數組中的查找

目錄 題目解題思路具體代碼題目 題目鏈接劍指offer&#xff1a;二維數組中的查找題目描述 在一個二維數組中&#xff08;每個一維數組的長度相同&#xff09;&#xff0c;每一行都按照從左到右遞增的順序排序&#xff0c;每一列都按照從上到下遞增的順序排序。請完成一個函數&a…