2022年7月5日 星期二

Linux 搜尋資料夾下檔案內的文字內容

例如,想要找「/home/test/」資料夾底下所有文件,含有「abc」內容的檔案名稱、在第幾行。

指令:

grep -rnw '/home/test/' -e 'abc'

說明:
-r, --recursive 遞迴讀取每個目錄下的文件
      Read  all files under each directory, recursively,
      following symbolic links only if they are on the command line.
      This is equivalent to the -d recurse option.

-n, --line-number 為文件每行標行號
      Prefix each line of output with the 1-based line number within its input file.
      (-n is specified by POSIX.)

-w, --word-regexp 選擇匹配的行
      Select only those lines containing matches that form whole words.
      The test is that the matching substring must either be at  the  beginning
      of the line, or preceded by a non-word constituent character.
      Similarly, it must be either at the end of the line or followed by a non-word
      constituent character.  Word-constituent characters are letters, digits, and the underscore.
-e PATTERN, --regexp=PATTERN 匹配文字樣式
      Use PATTERN as the pattern.  This can be used to specify multiple search patterns,
      or to protect a pattern beginning with a hyphen (-).  (-e is specified by POSIX.)


參考:



遠端桌面 windows 鎖定螢幕

[環境]
Win10


[問題]
使用 Chrome 遠端桌面完,想將螢幕鎖定,但無法直接按「Win」+「L」,也沒傳送「Win」+「L」功能。


[解決]
方法一:
先選擇傳送 「Ctrl」+「Alt」+「Del」,即可選擇「鎖定」。

方法一:
於 CMD,下螢幕鎖定指令:
rundll32.exe user32.dll, LockWorkStation



參考:



2022年6月23日 星期四

連結的 HTTP Referer 不見?

[狀況]
從 https://aa.example.com 連結到 http://bb.example.com
但在 http://bb.example.com 的 request header 沒有 Referer 資料


[原因]
瀏覽器(Chrome 103.0.5060.53)的 Referrer-Policy 預設值為 strict-origin-when-cross-origin
此時從 HTTPS 的網站,連結到 HTTP 網站,不傳送 Referer 資料


[解決]
因為我只需要 https://aa.example.com/ 這樣的 Origin(<scheme>://<hostname>:<port>) 資料,
不需要後面的 path、querystring,
所以於 https://aa.example.com 網站,將 Referrer-Policy 改為 origin,
如此在 HTTPS -> HTTP 時,仍會傳送包含  https://aa.example.com/ 的 Referer 資料
(注意:以下設定都是用正確拼寫的 Referrer)
  • 方法1:
    於 Web Server(以 Nginx 為例),設定 header ,將 Referrer-Policy 改為 origin:
    add_header 'Referrer-Policy' 'origin';
  • 方法2:
    於 HTML 頁面,設定 referrer ,將 Referrer-Policy 改為 origin:
    <meta name="referrer" content="origin">
  • 方法3:
    於連結,設定 referrerpolicy ,將 Referrer-Policy 改為 origin:
    <a href="http://bb.example.com/" referrerpolicy="origin" target="_blank">test</a>



[Referrer-Policy 的設定值]
引用:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
  • no-referrer:
    The Referer header will be omitted: sent requests do not include any referrer information.
  • no-referrer-when-downgrade:
    Send the origin, path, and querystring in Referer when the protocol security level stays the same or improves (HTTP→HTTP, HTTP→HTTPS, HTTPS→HTTPS). Don't send the Referer header for requests to less secure destinations (HTTPS→HTTP, HTTPS→file).
  • origin:
    Send only the origin in the Referer header. For example, a document at https://example.com/page.html will send the referrer https://example.com/.
  • origin-when-cross-origin:
    When performing a same-origin request to the same protocol level (HTTP→HTTP, HTTPS→HTTPS), send the origin, path, and query string . Send only the origin for cross origin requests and requests to less secure destinations (HTTPS→HTTP).
  • same-origin:
    Send the origin, path, and query string for same-origin requests. Don't send the Referer header for cross-origin requests.
  • strict-origin:
    Send only the origin when the protocol security level stays the same (HTTPS→HTTPS). Don't send the Referer header to less secure destinations (HTTPS→HTTP).
  • strict-origin-when-cross-origin (default):
    Send the origin, path, and querystring when performing a same-origin request. For cross-origin requests send the origin (only) when the protocol security level stays same (HTTPS→HTTPS). Don't send the Referer header to less secure destinations (HTTPS→HTTP).



參考:

2022年5月5日 星期四

MySQL(MariaDB) INSERT INTO ... ON DUPLICATE KEY UPDATE,只更新符合條件的資料

INSERT INTO ... ON DUPLICATE KEY UPDATE 沒辦法用 WHERE 條件過濾出要更新的資料,
但要更新的值,可以用 IF 條件來控制。
讓不欲更新的資料,用原值更新,效果便猶如沒更新過,而只更新其他資料。

[範例]
一資料表test,三個欄位 id(主鍵)、aa(int)、bb(int)。
新增(INSERT INTO)資料時,若資料(id)已存在,則更新 aa、bb 兩欄位資料,
但若原本的 bb 資料小於 100,則不更新 bb:
INSERT INTO test (id, aa, bb)
  VALUES (8, 123, 456)
ON DUPLICATE KEY UPDATE
  aa = VALUES(aa),
  bb = IF(bb<100, bb, VALUES(bb));


[注意]
如果有一筆資料(id, aa, bb) => (10, 1, 2)
INSERT INTO test (id, aa, bb)
  VALUES (10, 100, 200)
ON DUPLICATE KEY UPDATE
  aa = VALUES(aa),
  bb = aa;
得到的結果是 (id, aa, bb) => (10, 100, 100)

將最後兩行順序調換:
INSERT INTO test (id, aa, bb)
  VALUES (10, 100, 200)
ON DUPLICATE KEY UPDATE
  bb = aa,
  aa = VALUES(aa);
得到的結果是 (id, aa, bb) => (10, 100, 1)

可發現,順序不同,結果不同
=> ON DUPLICATE KEY UPDATE 若要取其他欄位的原值,須排在其他欄位修改之前。



所以最初的例子「若原本的 bb 資料小於 100,則不更新 bb」,
如果改成「若原本的 bb 資料小於 原本aa,則不更新 bb」,
則須注意 aa、bb 修改的順序,避免比較到 aa 修改後的值:
INSERT INTO test (id, aa, bb)
  VALUES (8, 123, 456)
ON DUPLICATE KEY UPDATE
  bb = IF(bb<aa, bb, VALUES(bb)),
  aa = VALUES(aa);



參考:



2022年5月3日 星期二

Andriod 使用 WebView 內嵌網頁簡易範例

  1. 新增一個 Empty Activity 專案


  2. AndroidManifest.xml 加網路權限
    <uses-permission android:name="android.permission.INTERNET" />
    最終 AndroidManifest.xml  內容:
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.testwebview">
        <uses-permission android:name="android.permission.INTERNET" />
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.TestWebView">
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

  3. 開啟 layout 檔案 activity_main.xml,刪掉預設的 TextView(Hello World!),放一個 WebView
    設定 id 為「myWebView」,layout_width、layout_height 屬性設為「0dp」
    (使用專案預設的 ConstraintLayout)


    WebView 屬性設定往下拉,找到 All Attributes 裡的 layout_constraints 設定
    layout_constraintBottom_toBottomOf、layout_constraintEnd_toEndOf、layout_constraintStart_toStartOf、layout_constraintTop_toTopOf 都設為「parent」

    最終 activity_main.xml 內容:
    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <WebView
            android:id="@+id/myWebView"
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

  4. MainActivity.java 內容
    package com.example.testwebview;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.webkit.WebSettings;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    
    public class MainActivity extends AppCompatActivity {
    
        WebView mWebView;
        WebSettings mWebSettings;
        //Android 9 (API level 28) 後,預設只能開啟 https 網站
        String url = "https://google.com/";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //mWebView = (WebView) findViewById(R.id.myWebView);
            mWebView = findViewById(R.id.myWebView);
            mWebSettings = mWebView.getSettings();
            //mWebSettings.setUserAgentString("app");
            mWebSettings.setJavaScriptEnabled(true);//開啟JS
            mWebSettings.setDomStorageEnabled(true);//開啟localStorage
            mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
    
            //若沒設定setWebViewClient(),則點WebView頁面的連結會呼叫系統瀏覽器開啟,不會保留在APP中
            mWebView.setWebViewClient(new WebViewClient());
            mWebView.loadUrl(url);
        }
    }

  5. 去除 APP 上方的 ActionBar 標題列,修改 res\values\themes.xml、res\values-night\themes.xml,改成 NoActionBar
    themes.xml
    <resources xmlns:tools="http://schemas.android.com/tools">
        <!-- Base application theme. -->
        <style name="Theme.TestWebView" parent="Theme.MaterialComponents.DayNight.NoActionBar">
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/purple_500</item>
            <item name="colorPrimaryVariant">@color/purple_700</item>
            <item name="colorOnPrimary">@color/white</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/teal_200</item>
            <item name="colorSecondaryVariant">@color/teal_700</item>
            <item name="colorOnSecondary">@color/black</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
            <!-- Customize your theme here. -->
        </style>
    </resources>
    themes.xml(night)
    <resources xmlns:tools="http://schemas.android.com/tools">
        <!-- Base application theme. -->
        <style name="Theme.TestWebView" parent="Theme.MaterialComponents.DayNight.NoActionBar">
            <!-- Primary brand color. -->
            <item name="colorPrimary">@color/purple_200</item>
            <item name="colorPrimaryVariant">@color/purple_700</item>
            <item name="colorOnPrimary">@color/black</item>
            <!-- Secondary brand color. -->
            <item name="colorSecondary">@color/teal_200</item>
            <item name="colorSecondaryVariant">@color/teal_200</item>
            <item name="colorOnSecondary">@color/black</item>
            <!-- Status bar color. -->
            <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
            <!-- Customize your theme here. -->
        </style>
    </resources>




[其他修改]






參考: