轉至:
最近需求要求定期從一個[定期更新的文件] 中解析員工信息 ,插入到數據庫中.
按理來說很簡單, 無非就是io流讀文件,然后crud balalalala.....
其實不是的, 我我寫的這個接口 ,要實現從遠程服務器上獲取文件然后入庫操作 . . . 問題來了, 我怎么去讀文件.
這樣就用到了linux的命令了 ,大致來說 , 從遠程服務器上獲取文件有好幾種方式 , scp快速獲取 sftp建立ssh連接 ,lftp連接 好像還有個rsync什么的,這個沒記住 ....
大致命令為
下載: 如果(-p端口號不好使 就替換成 -oPort=端口號)
scp -p端口號 遠程服務器用戶@遠程服務器ip:文件路徑 本地存放路徑
例子: scp -p22 root@10.10.10.168:/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。。。。
第一種:
<strong>#!/usr/bin/bash // 這個頭部很重要</strong> 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 命令
貼一下代碼吧


直接用scp -p22 root@10.10.10.153:/export/123.txt /home/root/123.txt 可以拉取到我本地
用 sftp -oPort(同一公司內服務器用-p就行)=22 root@10.10.10.153 , 可以直接連接上 不需要輸入密碼了;
然后 cd /export/ ===>>>到遠程目錄下
cd /home/root/ ===>>>到本地目錄下
get 文件名 ===>>>妥妥的復制過來了(put也一樣)
lftp 上面寫過了.
把java代碼也粘一下.(目前還不想使用github,因為比較菜 ,不想過多把精力放在這上面 ,文章也懶得排版,想到哪就寫到哪了.....有問題加我球球號952288306 交流)
執行腳本的java代碼:
import java.io.*; /** * * @author * 執行腳本的工具類 */ 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 * */ 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 ""; } }
