bash - windows subsystem for linux has no installed distributions.




كيفية تعيين متغير على إخراج أمر في باش؟ (9)

بعض الحيل bash يمكنني استخدامها لضبط المتغيرات من الأوامر

التعديل الثاني 2018-02-12: إضافة طريقة خاصة ، انظر في أسفل هذا!

2018-01-25 تحرير: إضافة دالة نموذجية ( لطباعة vars حول استخدام القرص)

أول طريقة قديمة وبسيطة متوافقة

myPi=`echo '4*a(1)' | bc -l`
echo $myPi 
3.14159265358979323844

متوافقة في الغالب ، الطريقة الثانية

وبما أن التعشيش يمكن أن يصبح ثقيلاً ، فقد تم تنفيذ هذا الأمر

myPi=$(bc -l <<<'4*a(1)')

عينة متداخلة:

SysStarted=$(date -d "$(ps ho lstart 1)" +%s)
echo $SysStarted 
1480656334

قراءة أكثر من متغير واحد (مع bashisms )

df -k /
Filesystem     1K-blocks   Used Available Use% Mounted on
/dev/dm-0         999320 529020    401488  57% /

إذا كنت أريد فقط استخدام القيمة:

array=($(df -k /))

يمكنك أن ترى متغير الصفيف :

declare -p array
declare -a array='([0]="Filesystem" [1]="1K-blocks" [2]="Used" [3]="Available" [
4]="Use%" [5]="Mounted" [6]="on" [7]="/dev/dm-0" [8]="999320" [9]="529020" [10]=
"401488" [11]="57%" [12]="/")'

ثم:

echo ${array[9]}
529020

لكنني أفضل هذا:

{ read foo ; read filesystem size used avail prct mountpoint ; } < <(df -k /)
echo $used
529020

read foo الأولى read foo سوف تخطي خط الرأس فقط (سيحتوي $foo المتغير على شيء مثل Filesystem 1K-blocks Used Available Use% Mounted on )

وظيفة عينة لملء بعض المتغيرات:

#!/bin/bash

declare free=0 total=0 used=0

getDiskStat() {
    local foo
    {
        read foo
        read foo total used free foo
    } < <(
        df -k ${1:-/}
    )
}

getDiskStat $1
echo $total $used $free

Nota: لا يُعد سطر declare مطلوبًا ، فقط للقراءة.

حول sudo cmd | grep ... | cut ... sudo cmd | grep ... | cut ...

shell=$(cat /etc/passwd | grep $USER | cut -d : -f 7)
echo $shell
/bin/bash

(يرجى تجنب cat غير مجدية! لذلك هذا هو مجرد 1 شوكة أقل:

shell=$(grep $USER </etc/passwd | cut -d : -f 7)

جميع الأنابيب ( | ) تعني شوكات. حيث يجب تشغيل عملية أخرى ، الوصول إلى القرص ، واستدعاءات المكتبات وما إلى ذلك.

لذا باستخدام sed للعينة ، سيحد من المعالجة الفرعية إلى شوكة واحدة فقط:

shell=$(sed </etc/passwd "s/^$USER:.*://p;d")
echo $shell

ومع bashisms :

ولكن بالنسبة إلى العديد من الإجراءات ، ومعظمها على الملفات الصغيرة ، يمكن أن يؤدي " bash " المهمة بنفسه:

while IFS=: read -a line ; do
    [ "$line" = "$USER" ] && shell=${line[6]}
  done </etc/passwd
echo $shell
/bin/bash

أو

while IFS=: read loginname encpass uid gid fullname home shell;do
    [ "$loginname" = "$USER" ] && break
  done </etc/passwd
echo $shell $loginname ...

الذهاب إلى أبعد حول تقسيم المتغير ...

ألقِ نظرة على إجابتي حول كيفية تقسيم سلسلة على محدد في Bash؟

بديل: تقليل الشوك باستخدام مهام طويلة الأمد في الخلفية

التعديل الثاني 2018-02-12: لمنع شوك متعددة مثل

myPi=$(bc -l <<<'4*a(1)'
myRay=12
myCirc=$(bc -l <<<" 2 * $myPi * $myRay ")

أو

myStarted=$(date -d "$(ps ho lstart 1)" +%s)
mySessStart=$(date -d "$(ps ho lstart $$)" +%s)

ولأن date و bc قد يعملان سطرا سطرا :

bc -l <<<$'3*4\n5*6'
12
30

date -f - +%s < <(ps ho lstart 1 $$)
1516030449
1517853288

يمكننا استخدام عملية خلفية طويلة الأمد لجعل الوظائف متكررة ، دون الحاجة إلى بدء شوكة جديدة لكل طلب:

mkfifo /tmp/myFifoForBc
exec 5> >(bc -l >/tmp/myFifoForBc)
exec 6</tmp/myFifoForBc
rm /tmp/myFifoForBc

(بالطبع ، يجب أن تكون FD 5 و 6 غير مستخدمة!) ... ومن هناك ، يمكنك استخدام هذه العملية من خلال:

echo "3*4" >&5
read -u 6 foo
echo $foo
12

echo >&5 "pi=4*a(1)"
echo >&5 "2*pi*12"
read -u 6 foo
echo $foo
75.39822368615503772256

في وظيفة newConnector

قد تجد وظيفة GitHub.Com الخاصة بي على GitHub.Com أو على موقعي الخاص (Nota on github ، هناك ملفان ، على موقعي ، وظيفة و demo مجمعة في ملف واحد يمكن الحصول عليه للاستخدام أو لمجرد العرض التجريبي)

عينة:

. shell_connector.sh

tty
/dev/pts/20

ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
  29019 pts/20   Ss     0:00 bash
  30745 pts/20   R+     0:00  \_ ps --tty pts/20 fw

newConnector /usr/bin/bc "-l" '3*4' 12

ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
  29019 pts/20   Ss     0:00 bash
  30944 pts/20   S      0:00  \_ /usr/bin/bc -l
  30952 pts/20   R+     0:00  \_ ps --tty pts/20 fw

declare -p PI
bash: declare: PI: not found

myBc '4*a(1)' PI
declare -p PI
declare -- PI="3.14159265358979323844"

تتيح لك وظيفة myBc استخدام مهمة الخلفية myBc بسيط ، وحتى الآن:

newConnector /bin/date '-f - +%s' @0 0
myDate '2000-01-01'
  946681200
myDate "$(ps ho lstart 1)" boottime
myDate now now ; read utm idl </proc/uptime
myBc "$now-$boottime" uptime
printf "%s\n" ${utm%%.*} $uptime
  42134906
  42134906

ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
  29019 pts/20   Ss     0:00 bash
  30944 pts/20   S      0:00  \_ /usr/bin/bc -l
  32615 pts/20   S      0:00  \_ /bin/date -f - +%s
   3162 pts/20   R+     0:00  \_ ps --tty pts/20 fw

من هناك ، إذا كنت ترغب في إنهاء إحدى عمليات الخلفية ، عليك فقط إغلاق ملف fd :

eval "exec $DATEOUT>&-"
eval "exec $DATEIN>&-"
ps --tty pts/20 fw
    PID TTY      STAT   TIME COMMAND
   4936 pts/20   Ss     0:00 bash
   5256 pts/20   S      0:00  \_ /usr/bin/bc -l
   6358 pts/20   R+     0:00  \_ ps --tty pts/20 fw

ليست هناك حاجة إلى wich ، لأن كل إغلاق FD عند الانتهاء من العملية الرئيسية.

لدي برنامج نصي بسيط جدًا يشبه ما يلي:

#!/bin/bash

VAR1="$1"    
MOREF='sudo run command against $VAR1 | grep name | cut -c7-'

echo $MOREF

عندما أقوم بتشغيل هذا البرنامج النصي من سطر الأوامر ونقوم بتمرير الوسيطات ، لن أحصل على أي إخراج. ومع ذلك ، عند تشغيل الأوامر المتضمنة في متغير $MOREF ، يمكنني الحصول على الإخراج.

أود أن أعرف كيف يمكن للمرء أن يأخذ نتائج الأمر الذي يحتاج إلى أن يتم تشغيله داخل برنامج نصي ، حفظه إلى متغير ، ثم إخراج هذا المتغير على الشاشة؟


أعرف ثلاث طرق للقيام بها:

1) وظائف مناسبة لمثل هذه المهام:

func (){
ls -l
}

استدعيها بالقول func

2) يمكن أيضًا أن يكون هناك حل مناسب آخر:

var="ls -l"
eval $var

3) يستخدم الثالث متغيرات مباشرة:

var=$(ls -l)
OR
var=`ls -l`

يمكنك الحصول على إخراج الحل الثالث بطريقة جيدة:

echo "$var"

وكذلك بطريقة سيئة:

echo $var

بالإضافة إلى backticks ، يمكنك استخدام $() ، الذي أجده أسهل في القراءة ، ويسمح بالتداخل.

OUTPUT="$(ls -1)"
echo "${OUTPUT}"

الاقتباس ( " ) يهم للحفاظ على قيم متعددة الأسطر.


تحتاج إلى استخدام إما

$(command-here)

أو

`command-here`

مثال

#!/bin/bash

VAR1="$1"
VAR2="$2"

MOREF=$(sudo run command against $VAR1 | grep name | cut -c7-)

echo $MOREF

فقط لتكون مختلفة:

MOREF=$(sudo run command against $VAR1 | grep name | cut -c7-)

في ما يلي طريقتان أخريان: يُرجى الانتباه إلى أن المساحة مهمة جدًا في bash حتى إذا كنت تريد تشغيل الأمر كما هو دون إدخال مسافات أكثر.

  1. يلي يعيّن harshil إلى L ثم يطبعه

    L=$"harshil"
    echo "$L"
    
  2. يلي يعين الإخراج من الأمر TR إلى L2. يتم تشغيل tr على متغير L1 آخر.

    L2=$(echo "$L1" | tr [:upper:] [:lower:])
    

كما أشاروا إليك بالفعل ، يجب استخدام "backticks".

البديل المقترح $(command) يعمل أيضاً ، كما أنه سهل القراءة ، ولكن لاحظ أنه صالح فقط مع قذائف bash أو korn (والقذائف المشتقة من تلك) ، لذلك إذا كانت النصوص الخاصة بك يجب أن تكون محمولة بالفعل على مختلف يونكس الأنظمة ، يجب عليك أن تفضل تدوين backticks القديم.


هذه طريقة أخرى ، جيدة للاستخدام مع بعض برامج تحرير النصوص غير القادرة على تسليط الضوء على كل كود معقد تقوم بإنشائه بشكل صحيح.

read -r -d '' str < <(cat somefile.txt)
echo "${#str}"
echo "$str"

تحديث (2018): الطريق الصحيح هو

$(sudo run command)

أنت تستخدم النوع الخطأ من الفاصلة العليا. أنت بحاجة إلى ` لا ' . تسمى هذه الشخصية "backticks" (أو "لهجة خطيرة").

مثله:

#!/bin/bash

VAR1="$1"
VAR2="$2"

MOREF=`sudo run command against "$VAR1" | grep name | cut -c7-`

echo "$MOREF"




command-line