shell腳本實現文件的自動上傳以及下載 scp sftp lftp 還有expect命令 2018年6月1日

最近需求要求定期從一個[定期更新的文件] 中解析員工信息 ,插入到數據庫中. 

    按理來說很簡單,  無非就是io流讀文件,然後crud balalalala.....

 其實不是的, 我我寫的這個接口 ,要實現從遠程服務器上獲取文件然後入庫操作 . . . 問題來了,  我怎麼去讀文件.

這樣就用到了linux的命令了 ,大致來說 , 從遠程服務器上獲取文件有好幾種方式 , scp快速獲取 sftp建立ssh連接 ,lftp連接  好像還有個rsync什麼的,這個沒記住 ....

 大致命令爲


下載: 如果(-p端口號不好使 就替換成 -oPort=端口號)

scp -p端口號   遠程服務器用戶@遠程服務器ip:文件路徑   本地存放路徑   

    

例子: scp -p22 [email protected]:/usr/wang.txt  /usr/wang.txt     這個好像不能scp的時候改名字

sftp -p端口號  遠程服務器用戶@遠程服務器ip 建立連接之後:

get  要下載的文件路徑+文件名    本地存儲路徑

put    本地存儲路徑   要上傳的文件路徑+文件名 

quit 或者exit  可以退出ssh連接

例子 懶得寫了, 直接截屏吧



lftp 這個我是和sftp 同時用的 有一個好處可以免登陸的:

現在上圖:.......

     碼的公司服務器好像斷了 (掀桌!), 算了不截屏了 , 老老實實碼字吧.. . . . . . .


這個是點擊之後 , 就會進入  

這個時候  cd  遠程服務器目錄    這個命令就是進入遠程服務器的目錄

               lcd  本地存放目錄      這個額命令就是進入本地需要存放的目錄

             get   需要下載文件名     

              put   需要上傳的文件名

quit或者   exit 退出       


其實我要說的命令直接百度就能搜到 , 接下來就是實現自動上傳或下載了 ,大致有三種 , 我實現了有兩種 , 看這個大神的

點擊打開大神總結

第一種:使用lftp+sftp 命令

第二種:使用expect 命令

第三種:配置免密 看這個寫得很清楚點擊打開鏈接  大致就是使用- keygen 生成密鑰,將公鑰交給遠程服務器以配置免登錄

注意:你用那個用戶獲取的密鑰,你就要cd到那個用戶的cd /用戶名/.ssh/公鑰文件   下, 我就是用admin用戶獲取到 ,但是發現進不去/root/.ssh/  目錄下 , 大概我是個接觸腳本兩天的小白把 ,maybe。。。。


第一種:

#!/usr/bin/bash    // 這個頭部很重要
trandt=`date +%Y%m%d`
lastdt=`date -d "$trandt -2 day " +%Y%m%d`
var1=dim_user_
var2=.txt
 #文件名
filename=${var1}${lastdt}${var2}   /需求上說的是文件名跟日期變動的,所以我的文件名這麼寫 ,   可以寫死的!
USER=wodemingzi
 #密碼
PASSWORD=wodemima
#下載文件目錄
#LOCAL=/usr/local/src/            文件admin沒有讀寫權限
LOCAL=/home/admin/   // 儘量放在這個目錄下吧  有的應用沒有其他文件夾的讀寫權限
#FTP目錄(待下載文件目錄)
 REMOTE=/jd_tfm_file/  
 #銀聯IP
IP=10.10.10.168
 #端口
PORT=2374
lftp -u ${USER},${PASSWORD} sftp://${IP}:${PORT}<<EOF
 cd ${REMOTE}
lcd ${LOCAL}
 #需要下載的文件
get ${filename}
EOF

這個腳本其實不算難 , 但是實現的時候非常的艱難 , 首先是腳本不能執行的問題 , 需要注意的地方我加粗了 這個文件的名字爲lftp.sh

是個shell腳本文件, 需要 是sh  lftp.sh 來運行的 . 

其次就是文件不能執行的問題:

文件權限需要用   chmod 777 腳本文件.sh   獲取權限      

+++++++++++++++++++++++++++今天先寫到這, 明天再寫吧++++++++++++++++++++++++++++++++

繼續寫:

文件獲取權限之後 ,使用sh  lftp.sh就可以執行了


但是有一個問題, 看貼圖吧


我使用cat命令,把腳本粘貼到命令行執行, 

wht?!!!沒有報告任何錯誤 , 直接就把遠程服務器文件get到了我本地指定目錄裏面。


錯誤.jpg

假裝有圖,  

發現執行到, 這裏 , 就不執行了 , 始終搞不懂到底是爲啥 , 百度了各大資料, 有人說 這是lftp命令沒裝好, 有人說這是沒有指定目錄, 還有人用./wang.sh 的方式 ,還有人說是用戶權限的問題 , 我把代碼粘出來就能執行你告訴我是權限的問題??!!!

總之全他麼的不好使 ,最後本人媳婦(大神)告訴我 ,你這個文件的聲明不對吧,,,shell腳本聲明頭應該是這樣的

#!/usr/bin/bash

看到我之前發的截圖嗎 , 頭部明顯不太對 , 好吧, 然後我就改了  ,然後繼續用

 sh  wang.sh  ;

發現還是不好使 ; 報的錯不粘出來了 , 這次是真的沒辦法了, 我就放棄了一段時間 ,然後幹別的去了......

=======n小時後, 我又開始驗證這段腳本 了, 不好使 , 不知道怎麼回事,我進入了這個大神的博客 , 我其實不想驗證的,因爲我一開始就害怕腳本是dos格式的 ,我就全刪了,然後在linux中手打了一遍的......

反正閒的蛋疼, 我就用

vi wang.sh     

按Esc , 輸入 冒號 ff見下面 

 : set ff                      ===>>> 得到的他麼的竟然是   'dos' , !!!!!!!!!!!這回真的是傷了

先弄好了吧 , 輸入 冒號 set ff=unix  

: set ff=unix       ,==>>>>再輸入 :set ff  發現就變成   unix  了 . 

好這次我繼續敲:  

 sh  wang.sh  ;    ^_^,終於成功了!!!!

第一種方式完成!!!!!

  總結: 腳本

        第一要先驗證腳本格式是什麼類型的,是dos 還是unix 的 ,這個很重要 鏈接在這裏

        https://blog.csdn.net/chengxuyuanyonghu/article/details/47340123

        第二,一定要注意頭部一定要正確, 確保你的命令在linux中已經安裝了

        第三,確保你的腳本文件時一個可執行的文件 , 不可執行,使用 chmod 777 文件名 獲取權限

      第四:這個我最後遇到了, 不過懶得再複述了. , 在你的腳本中設置 本地存放路徑(lcd 路徑) 的時候 ,一定要確保你的當前用戶(不管是root還是 admin還是其他) 是擁有這個目錄的讀寫權限的,這個存放目錄建議就放在/home/用戶名/  這個目錄下最靠譜.

第五: 沒了.(對了,就算做到了這些, 也要確保遠程服務器和本地服務器的連通性 ,先使用單行命令,是不是能連通 ,然後再去測腳本)


============================o(╥﹏╥)o=============================

第二種方式: 使用expect 命令的方式 , 

很不幸, 我的這個不好使 , 一直報告找不到

spawn  not found 

     我確實安裝了 expect 命令

貼一下代碼吧


沒辦法 , 我試了上述那幾個總結, 依舊不好使

希望你們能發現是什麼問題:

首先使用命令安裝了expect 我使用 exp expect.exp 也跑不動這個腳本.

總之這個就棄用了.

============================o(╥﹏╥)o=============================

第三種方式: 配公鑰

        也是最方便的最快捷的方式 配置公鑰的方式,配置完了可以直接使用scp 命令  ,sftp 命令 ,lftp 命令 一行就把文件neng過來!

上面寫過鏈接了, 再發一遍點擊打開鏈接

寫的很清楚了, 使用

ssh-keygen     ===>>然後一路回車 ,

會生成一個小圖片 ,圈圈點點之類的 , 同時會在你的 /home/用戶名/.ssh/  家目錄下生成  公鑰和私鑰,

私鑰文件(id_rsa)和公鑰文件(id_rsa.pub)   公鑰文件 使用 cat  id_rsa.pub   命令

打開 , 將裏面的內容複製到===>>>>遠程服務器下同級目錄下的authorized_keys(沒有這個文件就創建一個就行) 中,多行要回車 隔開.

直接拿大神截圖過來用了,參考下......-_-||(公司又斷網了)


直接用scp  -p22  [email protected]:/export/123.txt  /home/root/123.txt    可以拉取到我本地

     用  sftp -oPort(同一公司內服務器用-p就行)=22  [email protected] , 可以直接連接上 不需要輸入密碼了;

 然後  cd  /export/           ===>>>到遠程目錄下

        cd /home/root/     ===>>>到本地目錄下

         get   文件名            ===>>>妥妥的複製過來了(put也一樣)

lftp 上面寫過了.


把java代碼也粘一下.(目前還不想使用github,因爲比較菜 ,不想過多把精力放在這上面 ,文章也懶得排版,想到哪就寫到哪了.....有問題加我球球號952288306 交流)

執行腳本的java代碼:

package com.jd.ecc.tianfu.tools;

import com.jd.ecc.tianfu.utils.FileUtils;

import java.io.*;

/**
 * 
 * @author wangwenbin1
 * 執行腳本的工具類
 */
public class JavaLinuxManager {
	
	public String Linuxscp(String img,String encode){
		String msg = null;
		try {
			 Process ps = Runtime.getRuntime().exec(img);
			 ps.waitFor();
			  msg = loadStream(ps.getErrorStream(),encode);
			 System.err.print(msg);
			 ps.destroy();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return msg;
	}
	
	static String loadStream(InputStream in,String encode) throws IOException {
        //把所有的數據讀取到這個字節當中
        byte[] b = new byte[1024];
        //聲明一個int存儲每次讀取到的數據
        int i = 0;
        //定義一個記錄索引的變量
        int index = 0;
        //循環讀取每個數據
        while((i=in.read())!=-1) {//把讀取的數據放到i中
            b[index] = (byte) i;
            index++;
        }
        return new String(b,encode==null?"utf-8":"gbk");
    }
	
//	 public static void main(String[] args) throws Exception {
//       File file =   new File("d:a.txt");
//         FileInputStream fileIn = new FileInputStream(file);
//         String s = loadStream(fileIn, FileUtils.encoded(file));
//         System.out.println(s);
//     }
}

controller很簡單, 就是 不少註解是swagger的 可以忽略 ,主要看加粗的部分

@ApiOperation(value = "執行java腳本")
@RequestMapping(value = "/runtime/img", produces = "application/json;charset=utf-8")
public RespData<Map<String, Object>> img(
        @ApiParam(value = "平臺ID", required = true) @RequestParam("platformId") Long platformId,
        @ApiParam(value = "腳本或者文件路徑(chmod 777 ./WEB-INF/shs/sftp.sh)", required = true) @RequestParam("img") String img, HttpServletRequest request,
        @ApiParam(value = "驗證碼", required=true) @RequestParam(value = "authcode",required = true)String authcode) {
    try {
        //  chmod 777 ./WEB-INF/shs/sftp.sh
        if ("XXX一個驗證碼省得別人惡意拼接XXXXX".equals(authcode)){
        JavaLinuxManager unix = new JavaLinuxManager();
        String linuxscp = unix.Linuxscp(img, null);
        Map<String,Object> map =  new HashMap<>();
        map.put("msg",linuxscp);
        return RespData.success(map);
        }else {
            return RespData.error("0000","驗證碼失敗!!!");
        }
    } catch (Exception e) {
        LOG.error("執行異常!", e);
        e.printStackTrace();
    }
    return RespData.error("0000", "執行異常");
}


附一個文件工具類:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;




/**
 * 讀取文本工具類
 * @author wangwenbin1
 *
 */
public class FileUtils {

   private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(FileUtils.class);
   
   /**
    * 判斷文件是否存在 不存在創建空文件
    * @param file
    * @return
    * @throws IOException
    */
   public static boolean isExistFile(File file) throws IOException {
        // 判斷是否存在
        if (file.exists()) {
            // 判讀是否是一個文件
            return file.isFile();
        } else if (file.length() == 0) {
            LOG.info("文件內容爲空");
        } else {
            LOG.info("文件不存在!");
        }
        return false;
    }
   
   /**
    * 判斷文件的編碼方式
    * @param file
    * @return
    * @throws IOException
    */
   public static String encoded(File file) throws IOException{
      InputStream in = new FileInputStream(file);
      byte[] b = new byte[3];
      in.read(b);
      in.close();
      if (b[0]==-17&&b[1]==-69&&b[2]==-65) {
         // 一般來說,utf-8 的前三個字符爲上述三個
         LOG.info("文件utf-8編碼!");
         return "utf-8";
      }else{
         LOG.info("文件gbk編碼!");
         return "gbk";
      }
   }
   /**
    * 讀取txt文件 返回Sting
    * @param path
    * @return
    * @throws IOException
    */
   public static String readTXTFile(String path) throws IOException {
        File file = new File(path);
        boolean existFile = isExistFile(file);
        if (existFile) {
            LOG.info("文件存在且內容非空!");
            String charset = encoded(file);
            InputStreamReader reader = new InputStreamReader(new FileInputStream(file), charset);
            BufferedReader bf = new BufferedReader(reader);
            StringBuffer sb = new StringBuffer();
            String text = "";
            while ((text = bf.readLine()) != null) {

                sb.append(text);
                sb.append(";");
                //sb.append("\r\n");
            }
            String sbNew = sb.substring(0, sb.length() - 1);
            reader.close();
            bf.close();
            return sbNew;
        }
        return "";
    }

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章