.txt faylida mavjud bo'lgan barcha kalit qiymat juftlarini bash skriptini ishlatib, qatorga o'tkazish

Quyida ko'rsatilgan json matniga ega bo'lgan "var" o'zgaruvchisi bor

 var='{ "user": "jack","password": "kilby","install":"False", "deploy":"False", "build":"123","ip":"0.0.0.0" }'

Agar .txt faylga yozsam

touch properties.txt

destdir=./properties.txt

if [ -f "$destdir" ]
then 
    echo "$var" > "$destdir"
fi

Keyin men quyida aytib o'tmoqchiman, keyingi ishlov berish uchun bir qator ichidagi barcha kalit qiymat juftlarini saqlash kerak

arr=( $(grep -o \"[^\"]*. properties.txt) )

Shunday qilib, er-xotin tirnoq ichida joylashgan barcha matnlar "arr"

lekin agar asosiy qiymat jufti quyida ko'rsatilgandek bo'lsa, masalan, agar qiymati bo'sh bo'lsa, "arr" bir ariza sifatida \ "arzimaydi deb bo'lmaydi.

{"k1":"","k2":"","k3":""}

Bunday holatda "arr" ga kirish uchun bo'sh joyga borish kerak.

Bash komandalaridan juda xabardor emasman. Har qanday yordamni qadrlang. Natijada "jq" kutubxonasi yordamida erishilsa, bu takliflar ham yoqadi. rahmat

0
Siz to'g'ri JSON parseriga ega bo'lgan tilni ishlatishdan yiroqsiz; Shellda yozilgan bunday narsalardan xabardor emasman.
qo'shib qo'ydi muallif chepner, manba
Agar JSON fayli mavjud bo'lmasa, JSON fayli mavjud emasmi?
qo'shib qo'ydi muallif chepner, manba
kerakli mahsulot nimadan iborat va siz kodingiz bilan qanday ishlab chiqarilgan?
qo'shib qo'ydi muallif George Vasiliou, manba
.txt faylida bu erda har bir kalit jufti juftidan keyin yangi qator kabi to'g'ri satr oxiriga ega bo'lmaydi. Faqatgina json tasmasi bor. "Var" kabi (bu savolda men aytdim).
qo'shib qo'ydi muallif Beatrix Kiddo, manba
@GeorgeVasiliou men qilayotgan barcha narsalar json simini o'z ichiga olgan txt faylidan barcha kalitlarni bir qatorga saqlashdir. Uning json fayli emasligini eslang
qo'shib qo'ydi muallif Beatrix Kiddo, manba
@chepner taklif uchun rahmat.
qo'shib qo'ydi muallif Beatrix Kiddo, manba
@GeorgeVasiliou Faqat bitta satr ichidagi barcha satrlarni qatorga saqlaydigan regeksga ehtiyoj bor. Agar biron-bir kalit uchun "qiymat" bo'sh bo'lsa, saqlash uchun bo'sh joy kerak
qo'shib qo'ydi muallif Beatrix Kiddo, manba

6 javoblar

jq is the tool to parse JSON from shell. You can parse JSON in other languages (python, PHP, ruby, GO, etc), but if you go that route, you might as well just write your whole program in that language.

Demak, bashdan jq foydalanasiz:

$ jq 'keys[] as $k | "\($k)=\(.[$k])"' <<<"$var" 
"build=123"
"deploy=False"
"install=False"
"ip=0.0.0.0"
"password=kilby"
"user=jack"

Agar siz ushbu juftlarni bash 4+ da assotsiativ qatorda bo'lishini xohlasangiz, buni qilishingiz mumkin:

$ declare -A a="( $(jq -r 'keys[] as $k | "[\($k)]=\"\(.[$k])\""' <<<"$var" ) )"
$ declare -p a
declare -A a=([build]="123" [install]="False" [ip]="0.0.0.0" [user]="jack" [deploy]="False" [password]="kilby" )

Bu o'zgarmaydigan indekslar yoki qiymatlar uchun yangi qatorlar mavjud bo'lmagan ekan, yaxshi ishlaydi. Keyinchalik murakkab ma`lumotlar bilan ishlashni ta'minlash uchun sizga murakkab ishlovchilar kerak. Yangi qatorlar xavfi mavjud bo'lsa, iltimos, bu haqda o'zingizning savolingizga javob bering.

1
qo'shib qo'ydi
@chepner - olib tashlandi va bir oz ko'proq tushuntirish pastga qo'shildi. 2:30 PM Men hozir qaerda bo'lsam, ertaga yana bu haqda qarab turaman.
qo'shib qo'ydi muallif ghoti, manba
@chepner, oxirgi declare misoli, yangi satrlardan boshqa hech narsa bilan himoyalanmaganiga ishonaman. Buni men qabul qila olaman. :) Ha, for loop, albatta, muammoli, shuning uchun ogohlantirish. Ehtimol, uni olib tashlashim kerak.
qo'shib qo'ydi muallif ghoti, manba
@ Chepner - yep, buni tushunib etdim, rahmat. Ruxsat etilgan.
qo'shib qo'ydi muallif ghoti, manba
Aslida, takliflar declare buyrug'i ( declare "$ p" ) ning bir qismi sifatida ishlatilishi uchun eval . Ammo jq orqali qaytarilgan takliflarning hech biri bo'sh joyni uchun pastadirida so'zlarni ajratishdan himoya qiladi; chiqdi ustidan yinelemek uchun vaqtini ishlatishingiz kerak va agar bu qiymatlar (yoki tugmachalar uchun, bu borada) yangi satrlarni o'z ichiga olmasa, faqat ishlaydi.
qo'shib qo'ydi muallif chepner, manba
Sizga eval kerak emas; agar p = "build = 123" bo'lsa, declare "$ p" qiymati declare = build = 123 kodi> 123 ni build ga kiriting.
qo'shib qo'ydi muallif chepner, manba
declare -A yondashuvi uchun ++: Men sizlarga bu kabi massivlarni boshlashingiz mumkinligini bilmasdim.
qo'shib qo'ydi muallif mklement0, manba

Tasavvur qiling:

$ jq -c 'keys[] as $k | ($k, .[$k])' <<< "$var"
"build"
"123"
"deploy"
"False"
"install"
"False"
"ip"
"0.0.0.0"
"password"
"kilby"
"user"
"jack"

Keyin bash buyrug'ini readarray yoki ibroni ishlatishingiz mumkin:

while read -r line
do ...
done

Qo'shimcha ma'lumot uchun jq-quvvatlash bo'limiga qarang.

Ogohlantirish

Sizning yakuniy maqsadingiz nima demoqchi emassiz, lekin men buni jqni yanada kengroq qo'llash uchun yanada yaxshiroq foydalanishni xohlayman deb o'ylayman.

1
qo'shib qo'ydi
Juda ko'p rahmat
qo'shib qo'ydi muallif Beatrix Kiddo, manba

Ushbu ma'lumotni to'g'ri yoki noto'g'ri talqin qilish uchun tanlagan usulni tekshirishni xohlamasdan, json ma'lumotlarini ajratish uchun tanlangan usulingiz bilan rozi bo'lmasam ham, sizning savolingizga javob berishga harakat qilaman.

Kodning ushbu nuqtasida arr nomli qator hosil qilasiz:

arr=( $(grep -o \"[^\"]*. properties.txt) )

Bashdan ushbu qatorda nima saqlanganligini aytib berishni so'rasangiz, javobni olasiz:

$ declare -p arr
declare -a arr=([0]="\"user\"" [1]="\"jack\"" [2]="\"password\"" [3]="\"kilby\"" \
[4]="\"install\"" [5]="\"False\"" [6]="\"deploy\"" [7]="\"\"" \
[8]="\"build\"" [9]="\"123\"" [10]="\"ip\"" [11]="\"0.0.0.0\"")

Javobni sinab ko'rish uchun "deploy": "false" - "deploy": "" ga bor maydonini o'zgartirdim. Bu yuqoridagi arr [7].

Sizning katalogingizdagi nuqsonli maydonlarni boshqarishning eng qulay usullaridan biri shu kabi arr qatorini quyidagicha bash almashtirish texnikasi yordamida qayta aniqlashdir:

$ arr=( ${arr[@]//\"\"/\"empty\"/} )
$ declare -p arr
declare -a arr=([0]="\"user\"" [1]="\"jack\"" [2]="\"password\"" [3]="\"kilby\"" \ 
[4]="\"install\"" [5]="\"False\"" [6]="\"deploy\"" [7]="\"empty\"/" \
[8]="\"build\"" [9]="\"123\"" [10]="\"ip\"" [11]="\"0.0.0.0\"")

Mind that arr[7] has changed to "empty" from previously ""

Aslida, sizning kodingiz bo'sh joylar uchun \ "\" qatorini saqlab qoladi, bu oddiy ""

O'zgartirishimdan so'ng arr [7] = \ "bo'sh \" kodini tavsiya eting, aks holda oddiy "empty" bilan bosib chiqariladi .Shubhasiz siz o'zgartirishingiz mumkin bu matn siz xohlagan narsalarga, ikkilamchi tirnoqlardan qochib qutulish orqali.

Results with your second var2={"k1":"","k2":"","k3":""}

$ var2='{"k1":"","k2":"","k3":""}'
$ echo "$var2" >properties.txt
$ cat properties.txt
{"k1":"","k2":"","k3":""}
$ arr=( $(grep -o \"[^\"]*. properties.txt) )
$ declare -p arr
declare -a arr=([0]="\"k1\"" [1]="\"\"" [2]="\"k2\"" [3]="\"\"" [4]="\"k3\"" [5]="\"\"")
$ arr=( ${arr[@]//\"\"/\"empty\"/} )
$ declare -p arr
declare -a arr=([0]="\"k1\"" [1]="\"empty\"/" [2]="\"k2\"" [3]="\"empty\"/" [4]="\"k3\"" [5]="\"empty\"/")
$ echo "${arr[@]}"
"k1" "empty"/ "k2" "empty"/ "k3" "empty"/

Izoh:
Ushbu yechim sizning kodingizga keyingi qadamni tavsiya qiladi. Men ma'lumotlaringizni manipulyatsiya qilish uslublarini (ya'ni sizning grep va boshqalar) sinovdan o'tkazmadim.

1
qo'shib qo'ydi
@BeatrixKiddo Bash-da standart qiymatlarni belgilashga o'xshash narsalarni yodda tutgan deb o'ylayman (qarang: wiki.bash -hackers.org/syntax/pe#use_a_default_value ). Ushbu metodlar sizning ishingizda ishlamaydi, chunki siz kirishlar mantiqiga ko'ra sizning arizangiz bo'sh emas.
qo'shib qo'ydi muallif George Vasiliou, manba
Fikringizni o'chirib tashlamoqchimisiz? Niiiceeeee!
qo'shib qo'ydi muallif George Vasiliou, manba
Siz haqsiz. Muammoni hal qildim. katta rahmat
qo'shib qo'ydi muallif Beatrix Kiddo, manba

Birinchidan, qatorning tarkibini qaytaradigan funksiya yarataman.

function myvar {
   cat << "END"
{ "user": "jack","password": "kilby","install":"False", "deploy":"False", "build":"123","ip":"0.0.0.0" }
END
}

Endi biz stringni satrlarni ',' qatorda kesib, maydonchalarni topib ajratishimiz mumkin.

myvar | tr ',' '\n' | sed 's/.*"\(.*\)".*\(".*"\).*/\1=\2/'

Now we have these, we can evaluating the result by sourcing it. Before sourcing it, we will use a tick to make it act as a file: <( echo "My output looks like a file")
OP asked for an array, but first I will show how to make environment vars.

source <(myvar | tr ',' '\n' | sed 's/.*"\(.*\)".*\(".*"\).*/\1=\2/')
echo "Environment variable build=${build}"

Endi biz uni assotsiativ qatorda to'ldirishni yaxshi ko'ramiz (Eslatma: faqat bash versiyasi 4).

declare -A arr
source <(myvar | tr ',' '\n' | sed 's/.*"\(.*\)".*\(".*"\).*/arr[\1]=\2/')
# Show that it worked
for key in ${!arr[@]}; do
     echo "Array[${key}]=${arr[${key}]}"
done
1
qo'shib qo'ydi
Men pastga tushish uchun sabab yo'q edi, lekin men bilaman deb o'ylayman. Mening yechimim jsonni yaxshiroq tushunadigan vositani qo'llash orqali kiritishda kichik o'zgarishlarga qarshilik ko'rsatmaydi. Ushbu javobni boshqa foydalanuvchilarga "bir .txt faylida mavjud kalit kalit juftlarini qanday qilib bir qatorda javon skriptiga ishlatishdan qat'i nazar, bir bash skriptini ishlatib, qanday qilib uzatish mumkin" degan savolni o'qish uchun yordam ko'rsatish uchun yubordim.
qo'shib qo'ydi muallif Walter A, manba
Taklifingiz uchun ko'p rahmat.
qo'shib qo'ydi muallif Beatrix Kiddo, manba

Tez javob berish uchun bolalar uchun ko'p narsalar. Muammoni quyidagi usul yordamida hal qildim

makeKeyValueArray (){
# remove colon and commas
IFS=':' read -ra ADDR <<< "$var"
IFS=',' read -ra ADDR2 <<< "${ADDR[@]}"

echo ${ADDR2[@]} > "$destdir"

#remove curly braces
sed 's/[{}]//g' $destdir > temp_ip_prop.txt
mv temp_ip_prop.txt $destdir



#store each item in a array "arr"
    cn=0;
        for i in `cat $destdir`
        do
        arr[$cn]=$i;
        ((cn=cn+1));
        done

}

Va keyin loop ichida "" qatorni o'z ichiga oladi. " Agar shunday bo'lsa, men bu maydonni bo'sh joy deb hisobladim.

Men qilgan xatolar ichida edi

arr = ($ (grep -o \ "[^ \"] * xususiyatlari.txt))

Bu har bir \ "qatorga saqlandi.

1
qo'shib qo'ydi

Ushbu javob echimlari muntazam qator ( 0 elementi) 1-ni oladi, element < kodi> 1 bog'liq qiymat, ...), savolda bo'lgani kabi; Bash v4 + assotsiativ qatorini yaratadigan yechim uchun ghoti ning foydali javobini ko'ring .

tl;dr:

Faqat standart yordam dasturlarini ishlatish:

readarray -t arr < <(grep -o '"[^"]*.' properties.txt | tr -d \")

Bash v3.x ekvivalenti:

arr=()
while IFS= read -r val; do
  arr+=( "$val" )
done < <(grep -o '"[^"]*.' properties.txt | tr -d \")

jq dan foydalanish:

readarray -t arr < <(jq -r 'keys_unsorted[] as $k | $k, .[$k]' properties.txt)

jq buyrug'i yig'ilishning foydali javobini o'zgartiradi: keys_unsorted tugmachalari buyurtma tartibida numaralandırılmasını beradi va -r , JSON-kodli emas, balki, bu holda er-xotin tirnoqlarni olib tashlash degan ma'noni anglatadi natijalar, xom qadriyatlar sifatida chiqishni ta'minlaydi.

Bash v3.x ekvivalenti:

arr=()
while IFS= read -r val; do
  arr+=( "$val" )
done < <(jq -r 'keys_unsorted[] as $k | "\($k)\n\(.[$k])"' properties.txt)

Avvalo birinchi narsa: agar imkon bo'lsa, jq -ni tanlang.

Yondashuvingiz bilan bog'liq muammolar:

  • grep -o \ "[^ \"] *. kiritilgan " arr = (...) belgilanadi, keyin qadriyatlarning bir qismi sifatida ajralib chiqiladi.

  • Bu muammolarni echish uchun tr -d \ " ga o'tish orqali tuzatish oson, lekin arr = ($ (...)) keyin bo'sh satrlarni e'tiborsiz qoldiradi, shuning uchun jarayonda bo'sh Kirish qiymatlarini yo'qotasiz.

  • odatda arr = ($ (...)) dan saqlanishingiz kerak, chunki (a) kiritilgan buyurtma belgilaridan qat'iy nazar, bo'shliq (so'zlarni ajratish) tomonidan $ (...) buyrug'ining o'rnini o'zgartiradi. (b) sukut, olingan so'zlarni filename kengayishiga (globbing) keltiradi.

Ikkala muammoni bartaraf etadigan xavfsiz alternativ - hech bo'lmaganda yo'nalishlarga asoslangan usuli bilan - Bash v4.0 dan beri mavjud readarray dan foydalanish; -t , o'qilgan chiziqlardan keyingi \ n chizig'ini chizadi.

Bash v3.x da, readarray -t arr ga mos keladigan deyarli ga tegishli bo'lgan tuzilmalarni o'qish uchun while - IFS = $ "\ n" read -d "-ra arr - shuningdek, bo'sh yozuvlarni e'tiborsiz qoldiradi .

0
qo'shib qo'ydi
Juda katta rahmat.
qo'shib qo'ydi muallif Beatrix Kiddo, manba