බාෂ් හි පරිසීමකය මත නූලක් බෙදන්නේ කෙසේද?


2064

මා සතුව මෙම නූල විචල්‍යයක ගබඩා කර ඇත:

IN="bla@some.com;john@home.com"

දැන් මා ;සතුව ඇති පරිසීමාවෙන් නූල් බෙදීමට මම කැමැත්තෙමි :

ADDR1="bla@some.com"
ADDR2="john@home.com"

මට අනිවාර්යයෙන්ම ADDR1සහ ADDR2විචල්‍යයන් අවශ්‍ය නොවේ . ඒවා අරාවෙහි මූලද්‍රව්‍ය නම් ඊටත් වඩා හොඳය.


පහත දැක්වෙන පිළිතුරු වලින් යෝජනා කිරීමෙන් පසුව, මම පහත සඳහන් දෑ සමඟ අවසන් කළෙමි.

#!/usr/bin/env bash

IN="bla@some.com;john@home.com"

mails=$(echo $IN | tr ";" "\n")

for addr in $mails
do
    echo "> [$addr]"
done

ප්‍රතිදානය:

> [bla@some.com]
> [john@home.com]

Internal_field_separator (IFS) සැකසීම සම්බන්ධ විසඳුමක් තිබුණි ;. එම පිළිතුරෙන් සිදුවූයේ කුමක්දැයි මට විශ්වාස නැත, ඔබ IFSපෙරනිමියට නැවත සකසන්නේ කෙසේද ?

RE: IFSවිසඳුම, මම මෙය උත්සාහ කළ අතර එය ක්‍රියාත්මක වේ, මම පැරණි දේ තබා IFSඑය නැවත පිහිටුවන්න:

IN="bla@some.com;john@home.com"

OIFS=$IFS
IFS=';'
mails2=$IN
for x in $mails2
do
    echo "> [$x]"
done

IFS=$OIFS

BTW, මම උත්සාහ කරන විට

mails2=($IN)

මට පළමු නූල ලැබුනේ එය ලූපයකින් මුද්‍රණය කරන විට පමණි, $INඑය වටා වරහන් නොමැතිව ක්‍රියා කරයි.


14
ඔබගේ "Edit2" සම්බන්ධයෙන්: ඔබට සරලව "IFS සකසන්න" හැකි අතර එය පෙරනිමි තත්වයට පැමිණේ. එය දැනටමත් පෙරනිමි නොවන අගයකට සකසා ඇතැයි අපේක්ෂා කිරීමට යම් හේතුවක් නොමැති නම් එය පැහැදිලිවම සුරැකීමට සහ ප්‍රතිස්ථාපනය කිරීමට අවශ්‍ය නැත. එපමණක් නොව, ඔබ මෙය කරන්නේ ශ්‍රිතයක් තුළ නම් (සහ, ඔබ එසේ නොවේ නම්, එසේ නොවන්නේ ඇයි?), ඔබට IFS දේශීය විචල්‍යයක් ලෙස සැකසිය හැකි අතර ඔබ ශ්‍රිතයෙන් ඉවත් වූ පසු එය එහි පෙර අගයට නැවත පැමිණේ.
ok ක්ස් මෝසෙස්

19
Ro බෘක්ස් මෝසස්: (අ) local IFS=...හැකි සෑම තැනකම භාවිතා කිරීම සඳහා +1 ; (ආ) -1 සඳහා unset IFS, මෙය හරියටම අයිඑෆ්එස් එහි පෙරනිමි අගයට නැවත සකසන්නේ නැත, නමුත් මම විශ්වාස කරන්නේ, සැකසූ අයිඑෆ්එස් අයිඑෆ්එස් ($ '\ ටී \ n') හි පෙරනිමි අගයට සමාන ලෙස ක්‍රියා කරන බව මම විශ්වාස කරමි. අභිරුචි අගයකට සකසා ඇති IFS සමඟ ඔබේ කේතය කිසි විටෙකත් ක්‍රියාත්මක නොවන බව අන්ධ ලෙස උපකල්පනය කරන්න; (ඇ) තවත් අදහසක් නම්, උපසිරැසියක් කැඳවීමයි: උප (IFS=$custom; ...)කුලකය IFS වලින් පිටවන විට එය මුලින් තිබූ දෙයට නැවත පැමිණේ.
dubiousjim

මට අවශ්‍ය වන්නේ ක්‍රියාත්මක කළ හැකි ස්ථානයක් විසි කළ යුත්තේ කොතැනටද යන්න තීරණය කිරීම සඳහා වූ මාර්ග පිළිබඳව ඉක්මන් බැල්මක් හෙලීමටයි ruby -e "puts ENV.fetch('PATH').split(':')". ඔබට පිරිසිදු බාෂ් රැඳී සිටීමට අවශ්‍ය නම් උදව් නොවනු ඇත, නමුත් බිල්ට් බෙදීමක් ඇති ඕනෑම ස්ක්‍රිප්ටින් භාෂාවක් භාවිතා කිරීම පහසුය.
නිකූගා

4
for x in $(IFS=';';echo $IN); do echo "> [$x]"; done
user2037659

2
එය අරාව ලෙස සුරැකීම සඳහා මට තවත් වරහන් කට්ටලයක් තබා \nඉඩක් සඳහා වෙනස් කිරීමට සිදු විය. ඉතින් අවසාන පේළිය mails=($(echo $IN | tr ";" " ")). දැන් මට mailsඅරාව අංකනය භාවිතා කිරීමෙන් mails[index]හෝ
ලූපයකින් නැවත කියවීමෙන්

Answers:


1250

ඔබට අභ්‍යන්තර ක්ෂේත්‍ර බෙදුම්කරු (IFS) විචල්‍යය සැකසිය හැකි අතර පසුව එය අරාවකට විග්‍රහ කිරීමට ඉඩ දෙන්න. මෙය විධානයකින් සිදු වූ විට, පැවරුම IFSසිදුවන්නේ එම තනි විධානයේ පරිසරයට පමණි (වෙත read). ඉන්පසු එය IFSවිචල්‍ය අගය අනුව ආදානය අරාවකට විග්‍රහ කරයි , එවිට අපට නැවත නැවත කළ හැක.

IFS=';' read -ra ADDR <<< "$IN"
for i in "${ADDR[@]}"; do
    # process "$i"
done

එය වෙන් කරන ලද අයිතම පේළියක් විග්‍රහ ;කර එය අරාවකට තල්ලු කරයි. සමස්තයක් ලෙස සැකසීමේ දේවල් $IN, එක් එක් වාරයේ ආදාන පේළියක් වෙන් කරන්නේ ;:

 while IFS=';' read -ra ADDR; do
      for i in "${ADDR[@]}"; do
          # process "$i"
      done
 done <<< "$IN"

22
මෙය බොහෝ විට හොඳම ක්‍රමයයි. අයිඑෆ්එස් එහි වර්තමාන වටිනාකමෙහි කොපමණ කාලයක් පවතිනු ඇත්ද, එය නොවිය යුතු විට එය සැකසීමෙන් මගේ කේතය අවුල් කළ හැකිද, එය අවසන් වූ පසු එය නැවත සකසන්නේ කෙසේද?
ක්‍රිස් ලුට්ස්

7
දැන් නිවැරදි කිරීමෙන් පසුව, කියවීමේ විධානයේ කාල සීමාව තුළ පමණි :)
ජොහැන්නස් ෂෝබ් - litb

14
ටික වේලාවක් භාවිතා නොකර ඔබට සියල්ල එකවර කියවිය හැකිය: -r -d '' -a addr <<< "in" # The -d '' මෙහි යතුරයි, එය පළමු නව රේඛාවේ නතර නොවන ලෙස කියවීමට කියයි ( එය පෙරනිමි -d වේ) නමුත් EOF හෝ NULL බයිට් තෙක් (ද්විමය දත්ත වල පමණක් සිදු වේ).
ලූනාත්

56
UcLucaBorrione වෙනම විධානයකට වඩා අර්ධ සළකුණක් හෝ වෙනත් බෙදුම්කරුවෙකු නොමැති IFSඑකම රේඛාවෙහි සැකසීම , එය එම විධානයට පරික්ෂා readකරයි - එබැවින් එය සැමවිටම " ප්‍රතිෂ් ored ාපනය " වේ; ඔබට අතින් කිසිවක් කිරීමට අවශ්‍ය නැත.
චාල්ස් ඩෆි

5
@imagineer මෙය $INඋපුටා දැක්වීමට අවශ්‍ය වන හෙරෙස්ට්රින්ග්ස් සහ අයිඑෆ්එස් හි දේශීය වෙනස්කම් සම්බන්ධ දෝෂයක් ඇත. දෝෂය bash4.3 හි සවි කර ඇත .
චෙප්නර්

978

සිට ගෙන bash shell පිටපත භේදය අරා :

IN="bla@some.com;john@home.com"
arrIN=(${IN//;/ })

පැහැදිලි කිරීම:

මෙම ඉදිකිරීම මඟින් ';'(ආරම්භක //මාධ්‍යය ගෝලීය ප්‍රතිස්ථාපනය) සියලු සිදුවීම් ( තනි අවකාශයක්) INසමඟ ප්‍රතිස්ථාපනය කරයි ' ', පසුව අවකාශය වෙන් කරන ලද නූල් අරාව ලෙස අර්ථ නිරූපණය කරයි (අවට වරහන් මඟින් කරන්නේ එයයි).

එක් එක් ';'අක්ෂර වෙනුවට අක්ෂරයක් ආදේශ කිරීම සඳහා කැරලි වරහන් තුළ භාවිතා වන වාක්‍ය ඛණ්ඩය පරාමිති විස්තාරණය' ' ලෙස හැඳින්වේ .

පොදු ගොචා කිහිපයක් තිබේ:

  1. මුල් නූලට අවකාශ තිබේ නම්, ඔබට IFS භාවිතා කිරීමට අවශ්‍ය වනු ඇත :
    • IFS=':'; arrIN=($IN); unset IFS;
  2. මුල් නූලට අවකාශයක් තිබේ නම් සහ පරිසීමකය නව රේඛාවක් නම්, ඔබට මෙය සමඟ IFS සැකසිය හැකිය :
    • IFS=$'\n'; arrIN=($IN); unset IFS;

86
මට එක් කිරීමට අවශ්‍යය: මෙය සියල්ලටම වඩා සරල ය, ඔබට ar {අරින් [1] with සමඟ අරාව මූලද්‍රව්‍ය වෙත පිවිසිය හැකිය (ඇත්ත වශයෙන්ම ශුන්‍යයන්ගෙන් ආරම්භ වේ)
Oz123

26
එය සොයා ගන්නා ලදි: variable {within තුළ විචල්‍යයක් වෙනස් කිරීමේ තාක්ෂණය 'පරාමිති ප්‍රසාරණය' ලෙස හැඳින්වේ.
කොමෝඩෝ ඩේව්

23
නැත, අවකාශයන් පවතින විට මෙය ක්‍රියාත්මක වේ යැයි මම නොසිතමි ... එය ',' 'බවට පරිවර්තනය කර අවකාශයෙන් වෙන් වූ අරාවක් සාදයි.
ඊතන්

12
ඉතා සංක්ෂිප්ත, නමුත් සාමාන්‍ය භාවිතය සඳහා අවවාද ඇත : කවචය වචන බෙදීම හා නූලට පුළුල් කිරීම අදාළ කරයි, එය නුසුදුසු විය හැකිය; එය සමඟ උත්සාහ කරන්න. IN="bla@some.com;john@home.com;*;broken apart". කෙටියෙන් කිවහොත්: ඔබේ ටෝකනවල කාවැද්දූ අවකාශ සහ / හෝ අක්ෂර තිබේ නම් මෙම ප්‍රවේශය බිඳී යනු ඇත. *වත්මන් ෆෝල්ඩරයේ ටෝකන ගැලපුම් ගොනු නාමයක් සෑදීම වැනි .
mklement0

53
වෙනත් හේතු නිසා මෙය නරක ප්‍රවේශයකි: නිදසුනක් ලෙස, ඔබේ නූල අඩංගු නම් ;*;, *එය වත්මන් නාමාවලියෙහි ඇති ගොනු නාම ලැයිස්තුවක් දක්වා පුළුල් වේ. -1
චාල්ස් ඩෆි

254

ඒවා වහාම සැකසීමට ඔබට අවශ්‍ය නැතිනම්, මම මෙය කිරීමට කැමතියි:

for i in $(echo $IN | tr ";" "\n")
do
  # process
done

අරාව ආරම්භ කිරීම සඳහා ඔබට මේ ආකාරයේ ලූපයක් භාවිතා කළ හැකිය, නමුත් එය කිරීමට පහසු ක්‍රමයක් තිබේ. කෙසේ වෙතත් මෙය උපකාරී වේ යැයි සිතමි.


ඔබ IFS පිළිතුර තබා ගත යුතුව තිබුණි. එය මා නොදන්නා දෙයක් මට ඉගැන්නුවා, එය අනිවාර්යයෙන්ම අරාවක් සෑදුවා, නමුත් මෙය ලාභ ආදේශකයක් කරයි.
ක්‍රිස් ලුට්ස්

මට පේනවා. ඔව්, මම මේ මෝඩ අත්හදා බැලීම් කරන බව මට පෙනේ, මම සෑම දෙයකටම පිළිතුරු දීමට උත්සාහ කරන සෑම අවස්ථාවකම මම අලුත් දේවල් ඉගෙන ගන්නෙමි. මම #bash IRC ප්රතිපෝෂණය සහ undeleted :) මත පදනම් දේවල් සංස්කරණය තියෙනවා
litb - ජොහැන්නස් Schaub

33
-1, ඔබ පැහැදිලිවම වචන විස්ථාපනය ගැන නොදැන සිටියි, මන්ද එය ඔබේ කේතයේ දෝෂ දෙකක් හඳුන්වා දෙන බැවිනි. එකක් නම් ඔබ $ IN උපුටා නොදක්වන අතර අනෙක ඔබ නව රේඛාවක් මවා පෙන්වන විට වචන විකාශනය සඳහා භාවිතා කරන එකම පරිසීමකයයි. ඔබ IN හි සෑම වචනයක්ම, සෑම පේළියක්ම නොව, අර්ධ සළකුණකින් වෙන් කරන ලද සෑම මූලද්‍රව්‍යයක්ම නිශ්චිතවම නොකියයි, නමුත් එය ක්‍රියා කරන ආකාරයට පෙනීමේ අතුරු effect ලයක් ඇති බව පෙනෙන්නට තිබුණද.
ලූනාත්

3
ඔබට එය "$ IN" දෝංකාරය ලෙස වෙනස් කළ හැකිය tr ';' '\ n' | කියවන අතරතුර -r ADDY; # ක්‍රියාවලිය "$ ADDY" කරන්න; ඔහුව වාසනාවන්ත කර ගැනීම සඳහා සිදු කර ඇති බව මම සිතමි :) මෙය දෙබලක ඇති බව සලකන්න, ඔබට
ලූපයෙන්

8
අදහස් දැක්වීමේදී විවාදය සාරාංශගත කිරීම සඳහා : සාමාන්‍ය භාවිතය සඳහා ගුහාවන් : කවචය වචන බෙදීම සහ නූලට පුළුල් කිරීම අදාළ කරයි, එය නුසුදුසු විය හැකිය; එය සමඟ උත්සාහ කරන්න. IN="bla@some.com;john@home.com;*;broken apart". කෙටියෙන් කිවහොත්: ඔබේ ටෝකනවල කාවැද්දූ අවකාශ සහ / හෝ අක්ෂර තිබේ නම් මෙම ප්‍රවේශය බිඳී යනු ඇත. *වත්මන් ෆෝල්ඩරයේ ටෝකන ගැලපුම් ගොනු නාමයක් සෑදීම වැනි .
mklement0

205

අනුකූල පිළිතුර

මෙය සිදු කිරීම සඳහා විවිධ ක්‍රම රාශියක් ඇත .

කෙසේ වෙතත්, එය පළමු සටහන වැදගත් bashවන විවිධ විශේෂ ලක්ෂණ (ඊනියා bashisms ) වෙනත් ඕනෑම වැඩ නැහැ.

විශේෂයෙන්, මෙම පෝස්ට් එකේ විසඳුම් සඳහා මෙන්ම නූල් වල ඇති අනෙක් ඒවා සඳහා භාවිතා කරන අරා , සහායක අරා සහ රටා ආදේශනය , බාෂිස්වාදයන් වන අතර බොහෝ අය භාවිතා කරන වෙනත් ෂෙල් වෙඩි යටතේ ක්‍රියා නොකරනු ඇත.

උදාහරණයක් ලෙස: මගේ ඩේබියන් ග්නූ / ලිනක්ස් හි සම්මත කවචයක් ඇත; තවත් ෂෙල් එකක් භාවිතා කිරීමට කැමති බොහෝ අය මම දනිමි; විශේෂ මෙවලමක් ද ඇත ඔහුගේම ෂෙල් පරිවර්තකය සමඟ ().

ඉල්ලූ නූල

ඉහත ප්‍රශ්නයේදී බෙදිය යුතු නූල:

IN="bla@some.com;john@home.com"

මගේ විසඳුම සුදු අවකාශය සහිත නූල් වලට ශක්තිමත් බව සහතික කිරීම සඳහා මම මෙම නූලෙහි නවීකරණය කරන ලද අනුවාදයක් භාවිතා කරමි, එමඟින් වෙනත් විසඳුම් බිඳ දැමිය හැකිය:

IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"

දී පරිසීමකය මත පදනම්ව බෙදීම් නූල් (අනුවාදය> = 4.2)

දී පිරිසිදු bash , අපි නිර්මාණය කළ හැක අරාව සඳහා තාවකාලික වටිනාකම මූලද්රව්ය සමග භේද IFS (මෙම ආදාන ක්ෂේත්රය වෙන්කර ). bashඅරාව නිර්වචනය කිරීමේදී මූලද්‍රව්‍ය අතර පරිසීමකයක් ලෙස සැලකිය යුත්තේ කුමන චරිත (ය) ද යන්න අයිඑෆ්එස් පවසයි :

IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"

# save original IFS value so we can restore it later
oIFS="$IFS"
IFS=";"
declare -a fields=($IN)
IFS="$oIFS"
unset oIFS

නවතම අනුවාද වලදී bash, අයිඑෆ්එස් අර්ථ දැක්වීමක් සහිත විධානයක් උපසර්ග කිරීමෙන් එම විධානය සඳහා පමණක් අයිඑෆ්එස් වෙනස් වන අතර එය වහාම පෙර අගයට යලි සකසයි. මෙයින් අදහස් කරන්නේ අපට ඉහත එක පේළියකින් කළ හැකි බවයි:

IFS=\; read -a fields <<<"$IN"
# after this command, the IFS resets back to its previous value (here, the default):
set | grep ^IFS=
# IFS=$' \t\n'

අර්ධ සළකුණු මත බෙදී ඇති INනමක් අරාවකට ගබඩා කර ඇති බව අපට පෙනේ fields:

set | grep ^fields=\\\|^IN=
# fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")
# IN='bla@some.com;john@home.com;Full Name <fulnam@other.org>'

(අපට මෙම විචල්‍යයන්ගේ අන්තර්ගතය ද ප්‍රදර්ශනය කළ හැකිය declare -p:)

declare -p IN fields
# declare -- IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
# declare -a fields=([0]="bla@some.com" [1]="john@home.com" [2]="Full Name <fulnam@other.org>")

දෙබලක හෝ බාහිර සම්පත් කැඳවීමක් නොමැති නිසා භේදය සිදු කිරීමට ඉක්මන්ම ක්‍රමය readඑය බව සලකන්න .

අරාව නිර්වචනය කළ පසු, ඔබට එක් එක් ක්ෂේත්‍රය සැකසීමට සරල පුඩුවක් භාවිතා කළ හැකිය (හෝ, ඒ වෙනුවට, ඔබ දැන් අර්ථ දක්වා ඇති අරාවේ සෑම අංගයක්ම):

# `"${fields[@]}"` expands to return every element of `fields` array as a separate argument
for x in "${fields[@]}" ;do
    echo "> [$x]"
    done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]

නැතහොත් මා කැමති මාරුවීමේ ප්‍රවේශයක් භාවිතයෙන් සැකසීමෙන් පසු ඔබට එක් එක් ක්ෂේත්‍රය අරාවෙන් ඉවත් කළ හැකිය :

while [ "$fields" ] ;do
    echo "> [$fields]"
    # slice the array 
    fields=("${fields[@]:1}")
    done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]

ඔබට අරාවෙහි සරල මුද්‍රණයක් අවශ්‍ය නම්, ඔබට එය ඉක්මවා යාමට අවශ්‍ය නොවේ:

printf "> [%s]\n" "${fields[@]}"
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]

යාවත්කාලීන කිරීම: මෑත > = 4.4

හි නවතම අනුවාද වලදී bash, ඔබට විධානය සමඟ සෙල්ලම් කළ හැකිය mapfile:

mapfile -td \; fields < <(printf "%s\0" "$IN")

මෙම වාක්‍ය ඛණ්ඩය විශේෂ අක්ෂර, නව රේඛා සහ හිස් ක්ෂේත්‍ර ආරක්ෂා කරයි!

ඔබට හිස් ක්ෂේත්‍ර ඇතුළත් කිරීමට අවශ්‍ය නැතිනම්, ඔබට පහත සඳහන් දෑ කළ හැකිය:

mapfile -td \; fields <<<"$IN"
fields=("${fields[@]%$'\n'}")   # drop '\n' added by '<<<'

සමඟ mapfile, ඔබට අරාව ප්‍රකාශ කිරීම මඟ හැරිය හැකි අතර, වෙන් කරන ලද මූලද්‍රව්‍යයන් මත ව්‍යංගයෙන් “ලූපයක්” ලබා ගත හැකිය.

myPubliMail() {
    printf "Seq: %6d: Sending mail to '%s'..." $1 "$2"
    # mail -s "This is not a spam..." "$2" </path/to/body
    printf "\e[3D, done.\n"
}

mapfile < <(printf "%s\0" "$IN") -td \; -c 1 -C myPubliMail

(සටහන: \0නූල් අවසානයේ හිස් ක්ෂේත්‍ර ගැන ඔබ තැකීමක් නොකරන්නේ නම් හෝ ඒවා නොපවතී නම්, ආකෘතියේ කෙළවරේ වැඩකට නැති ය.)

mapfile < <(echo -n "$IN") -td \; -c 1 -C myPubliMail

# Seq:      0: Sending mail to 'bla@some.com', done.
# Seq:      1: Sending mail to 'john@home.com', done.
# Seq:      2: Sending mail to 'Full Name <fulnam@other.org>', done.

නැතහොත් ඔබට භාවිතා කළ හැකි <<<අතර, ක්‍රියාකාරීත්වය තුළ එය එකතු කරන නව රේඛාව අතහැර දැමීමට යම් සැකසුම් ඇතුළත් වේ:

myPubliMail() {
    local seq=$1 dest="${2%$'\n'}"
    printf "Seq: %6d: Sending mail to '%s'..." $seq "$dest"
    # mail -s "This is not a spam..." "$dest" </path/to/body
    printf "\e[3D, done.\n"
}

mapfile <<<"$IN" -td \; -c 1 -C myPubliMail

# Renders the same output:
# Seq:      0: Sending mail to 'bla@some.com', done.
# Seq:      1: Sending mail to 'john@home.com', done.
# Seq:      2: Sending mail to 'Full Name <fulnam@other.org>', done.

දී පරිසීමකය මත පදනම්ව බෙදීම් නූල්

ඔබට භාවිතා කළ නොහැකි bashනම්, හෝ ඔබට විවිධ ෂෙල් වෙඩි භාවිතා කළ හැකි යමක් ලිවීමට අවශ්‍ය නම්, ඔබට බොහෝ විට bashisms භාවිතා කළ නොහැක - තවද ඉහත විසඳුම් සඳහා අප භාවිතා කළ අරා මෙයට ඇතුළත් වේ.

කෙසේ වෙතත්, නූලක “මූලද්‍රව්‍ය” ඉක්මවා යාමට අපට අරා භාවිතා කිරීමට අවශ්‍ය නොවේ. රටාවක පළමු හෝ අවසාන සිදුවීමෙන් නූලක උපස්ථර මකා දැමීම සඳහා බොහෝ කවච වල සින්ටැක්ස් භාවිතා වේ . *අක්ෂර ශුන්‍ය හෝ වැඩි ගණනක් නියෝජනය කරන ආදේශක කාඩ්පතක් බව සලකන්න :

(මෙතෙක් පළ කර ඇති කිසිදු විසඳුමක මෙම ප්‍රවේශය නොමැතිකම මා මෙම පිළිතුර ලිවීමට ප්‍රධාන හේතුවයි;)

${var#*SubStr}  # drops substring from start of string up to first occurrence of `SubStr`
${var##*SubStr} # drops substring from start of string up to last occurrence of `SubStr`
${var%SubStr*}  # drops substring from last occurrence of `SubStr` to end of string
${var%%SubStr*} # drops substring from first occurrence of `SubStr` to end of string

Score_Under විසින් පැහැදිලි කළ පරිදි :

#සහ නූල් ආරම්භයේ සහ අවසානයේ පිළිවෙලින් %හැකි කෙටිම ගැලපෙන උපස්ථරය මකා දමන්න , සහ

##හා %%දිගම හැකි ගැලපෙන substring මකන්න.

ඉහත වාක්‍ය ඛණ්ඩය භාවිතා කරමින්, පරිමිතිය දක්වා හෝ පසුව උපස්ථරයන් මකා දැමීමෙන් අපට “මූලද්‍රව්‍ය” උපස්ථරයෙන් උපුටා ගන්නා ප්‍රවේශයක් නිර්මාණය කළ හැකිය.

පහත කේත අවහිරය හොඳින් ක්‍රියාත්මක වේ (මැක් ඕඑස් ඇතුළුව bash),, , සහ ගේ :

IN="bla@some.com;john@home.com;Full Name <fulnam@other.org>"
while [ "$IN" ] ;do
    # extract the substring from start of string up to delimiter.
    # this is the first "element" of the string.
    iter=${IN%%;*}
    echo "> [$iter]"
    # if there's only one element left, set `IN` to an empty string.
    # this causes us to exit this `while` loop.
    # else, we delete the first "element" of the string from IN, and move onto the next.
    [ "$IN" = "$iter" ] && \
        IN='' || \
        IN="${IN#*;}"
  done
# > [bla@some.com]
# > [john@home.com]
# > [Full Name <fulnam@other.org>]

විනෝද වන්න!


15
මෙම #, ##, %, සහ %%ආෙද්ශක රටකින් (ඔවුන් මකා කොපමණ සඳහා) මතක තබා ගැනීමට පහසු පැහැදිලි කිරීමක් දේ ඇති: #හා %කෙටිම හැකි ගැලපෙන සංගීත මකා දැමීම, සහ ##සහ %%ඇති විය හැකි දිගම මකන්න.
ලකුණු_අන්ඩර්

1
IFS=\; read -a fields <<<"$var"නව රේඛා වල අසමත් වීම සහ පසුපස නව රේඛාවක් එක් කිරීම. අනෙක් විසඳුම පසුපස හිස් ක්ෂේත්‍රයක් ඉවත් කරයි.
අයිසැක්

ෂෙල් පරිසීමකය යනු වඩාත් අලංකාර පිළිතුර, කාල පරිච්ඡේදයයි.
එරික් චෙන්

අවසාන විකල්පය වෙනත් තැනක සකසා ඇති ක්ෂේත්‍ර බෙදුම්කරුවන්ගේ ලැයිස්තුවක් සමඟ භාවිතා කළ හැකිද? උදාහරණයක් ලෙස, මෙය ෂෙල් ස්ක්‍රිප්ට් එකක් ලෙස භාවිතා කිරීමට මම අදහස් කරමි, ස්ථානීය පරාමිතියක් ලෙස ක්ෂේත්‍ර බෙදුම්කරුවන්ගේ ලැයිස්තුවක් සම්මත කරන්න.
sancho.s ReinstateMonicaCellio

ඔව්, පුඩුවක් තුළ:for sep in "#" "ł" "@" ; do ... var="${var#*$sep}" ...
එෆ්. හවුරි

186

cutවිධානය සඳහන් කරමින් පිළිතුරු කිහිපයක් මම දැක ඇත්තෙමි , නමුත් ඒවා සියල්ලම මකා දමා ඇත. කිසිවෙකු ඒ ගැන විස්තාරණය නොකිරීම ටිකක් අමුතු දෙයක්, මන්ද එය මේ ආකාරයේ දෙයක් කිරීම සඳහා වඩාත් ප්‍රයෝජනවත් විධානයන්ගෙන් එකක් යැයි මම සිතමි, විශේෂයෙන් වෙන් කරන ලද ලොග් ගොනු විග්‍රහ කිරීම සඳහා.

මෙම විශේෂිත උදාහරණය බාෂ් ස්ක්‍රිප්ට් අරාවකට බෙදීමේදී, trබොහෝ විට වඩා කාර්යක්ෂම, නමුත් cutභාවිතා කළ හැකි අතර, ඔබට නිශ්චිත ක්ෂේත්‍ර මැදින් ඇද ගැනීමට අවශ්‍ය නම් වඩාත් effective ලදායී වේ.

උදාහරණයක්:

$ echo "bla@some.com;john@home.com" | cut -d ";" -f 1
bla@some.com
$ echo "bla@some.com;john@home.com" | cut -d ";" -f 2
john@home.com

ඔබට එය පැහැදිලිවම ලූපයකට දැමිය හැකි අතර, එක් එක් ක්ෂේත්‍රය ස්වාධීනව ඇද ගැනීමට -f පරාමිතිය නැවත කරන්න.

ඔබට මෙවැනි පේළි සහිත වෙන් කළ ලොග් ගොනුවක් ඇති විට මෙය වඩාත් ප්‍රයෝජනවත් වේ:

2015-04-27|12345|some action|an attribute|meta data

cutcatමෙම ගොනුවට හැකි වීම සහ වැඩිදුර සැකසීම සඳහා විශේෂිත ක්ෂේත්‍රයක් තෝරා ගැනීම ඉතා පහසුය .


6
භාවිතා කිරීම සඳහා කුඩෝස් cut, එය කාර්යය සඳහා නිවැරදි මෙවලමයි! එම ෂෙල් හැක් වලට වඩා බොහෝ දේ ඉවත් කර ඇත.
මිස්ටර්මියාගි

4
මෙම ප්‍රවේශය ක්‍රියාත්මක වන්නේ ඔබ කල්තියාම මූලද්‍රව්‍ය ගණන දන්නේ නම් පමණි; ඔබට එය වටා තවත් තර්කනයක් වැඩසටහන්ගත කිරීමට අවශ්‍ය වනු ඇත. එය සෑම මූලද්රව්යයක් සඳහාම බාහිර මෙවලමක් ද ක්රියාත්මක කරයි.
uli42

මම සීඑස්වී එකක හිස් නූලක් වළක්වා ගැනීමට උත්සාහ කළෙමි. දැන් මට නිශ්චිත 'තීරු' අගය ද පෙන්වා දිය හැකිය. දැනටමත් ලූපයක භාවිතා කර ඇති IFS සමඟ වැඩ කරන්න. මගේ තත්වය බලාපොරොත්තු වූවාට වඩා හොඳයි.
ලුවී ලොඩෝග් ට්‍රොට්ටියර්

හැඳුනුම්පත් සහ PID අදින්නද ඉතා ප්‍රයෝජනවත් වේ
මිලෝස් ග ru ජික්

මෙම පිළිතුර පිටු භාගයකට වඩා පහළට අනුචලනය කිරීම වටී :)
Gucu112

125

මෙය මට ප්‍රයෝජනවත් විය:

string="1;2"
echo $string | cut -d';' -f1 # output is 1
echo $string | cut -d';' -f2 # output is 2

1
එය ක්‍රියාත්මක වන්නේ තනි අක්ෂර පරිසීමකය සමඟ පමණක් වුවද, OP සොයමින් සිටියේ එයයි (අර්ධ සළකුණකින් වෙන් කරන ලද වාර්තා).
ගයිපැඩොක්

මීට වසර හතරකට පමණ පෙර @ අශෝක් විසින් ද, මීට වසරකට පෙර @ ඩග් ඩබ්ලිව් විසින් , ඔබේ පිළිතුරට වඩා වැඩි තොරතුරු සහිතව පිළිතුරු සපයන ලදී. කරුණාකර අනෙක් ඒවාට වඩා වෙනස් විසඳුමක් පළ කරන්න.
MAChitgarha

91

මෙම ප්‍රවේශය ගැන:

IN="bla@some.com;john@home.com" 
set -- "$IN" 
IFS=";"; declare -a Array=($*) 
echo "${Array[@]}" 
echo "${Array[0]}" 
echo "${Array[1]}" 

මූලාශ්රය


7
+1 ... නමුත් මම විචල්ය "අරේ" ලෙස නම් නොකරමි ... සුරතල් පීව් මම අනුමාන කරමි. හොඳ විසඳුමක්.
යස්මිර් රමිරෙස්

14
+1 ... නමුත් "කට්ටලය" සහ ප්‍රකාශ කිරීම -a අනවශ්‍යය. ඔබටත් භාවිතා කළ හැකියIFS";" && Array=($IN)
ata

+1 පැත්තක සටහනක් පමණි: පැරණි අයිඑෆ්එස් තබා එය නැවත පිහිටුවීම නිර්දේශ කළ යුතු නොවේද? (ඔහුගේ සංස්කරණය 3 හි ස්ටෙෆාන් බී විසින් පෙන්වා ඇති පරිදි) මෙහි ගොඩබසින පුද්ගලයින් (සමහර විට විසඳුමක් පිටපත් කර ඇලවීම) මේ ගැන
නොසිතනු ඇත

6
-1: පළමුව, @ata හරි, මෙහි ඇති බොහෝ විධානයන් කිසිවක් නොකරයි. දෙවනුව, එය අරාව සෑදීම සඳහා වචන බෙදීම භාවිතා කරයි, එසේ කරන විට ගෝලීය ප්‍රසාරණය වීම වැළැක්වීමට කිසිවක් නොකරයි (එබැවින් ඔබට ඕනෑම අරාව මූලද්‍රව්‍යයක ග්ලෝබ් අක්ෂර තිබේ නම්, එම මූලද්‍රව්‍ය ගැලපෙන ගොනු නාම වලින් ප්‍රතිස්ථාපනය වේ).
චාල්ස් ඩෆි

1
භාවිතා කිරීමට යෝජනා කරන්න $'...': IN=$'bla@some.com;john@home.com;bet <d@\ns* kl.com>'. එවිට echo "${Array[2]}"නව රේඛාවක් සමඟ නූලක් මුද්‍රණය කෙරේ. set -- "$IN"මෙම නඩුවේදී ද අවශ්‍ය වේ. ඔව්, ගෝලීය ව්‍යාප්තිය වැළැක්වීම සඳහා විසඳුමට ඇතුළත් විය යුතුය set -f.
ජෝන්_වෙස්ට්

80

ඔබේ ගැටලුව විසඳීමට හොඳම හා කාර්යක්ෂම විධානය AWK යැයි මම සිතමි . සෑම ලිනක්ස් බෙදාහැරීමකම පාහේ AWK පෙරනිමියෙන් ඇතුළත් කර ඇත.

echo "bla@some.com;john@home.com" | awk -F';' '{print $1,$2}'

ලබාදේවි

bla@some.com john@home.com

අමුතු මුද්‍රණ ක්ෂේත්‍රය නැවත අර්ථ දැක්වීමෙන් ඔබට සෑම විද්‍යුත් තැපැල් ලිපිනයක්ම ගබඩා කළ හැකිය.


3
හෝ ඊටත් වඩා සරලයි: echo "bla@some.com; john@home.com" | awk 'BEGIN {RS = ";"} {print}'
Jaro

@ ජාරෝ කොමා සමඟ නූලක් ඇති අතර එය රේඛා වලට නැවත ආකෘතිකරණය කිරීමට අවශ්‍ය වූ විට මෙය මට හොඳින් ක්‍රියාත්මක විය. ස්තූතියි.
ඇක්වාරෙල්

එය මෙම තත්වය තුළ ක්‍රියාත්මක විය -> "echo" $ SPLIT_0 "| awk -F 'inode =' '{print $ 1}'"! අක්ෂර (";") වෙනුවට atrings ("inode =") භාවිතා කිරීමට උත්සාහ කිරීමේදී මට ගැටළු ඇති විය. Ar 1, $ 2, $ 3, $ 4 අරාවෙහි ස්ථාන ලෙස සකසා ඇත! අරාව සැකසීමේ ක්‍රමයක් තිබේ නම් ... වඩා හොඳයි! ස්තූතියි!
එඩ්වාඩෝ ලුසියෝ

@EduardoLucio, සමහරවිට, ප්රථමයෙන් ඔබේ පරිසීමකය වෙනුවට කළ හැකි දේ මම මේ ගැන කල්පනා කරනවා ඇත inode=බවට ;උදාහරණයක් වශයෙන් sed -i 's/inode\=/\;/g' your_file_to_process, පසුව අර්ථ -F';'අයදුම් කරන විට awk, ඔබට උපකාර කළ හැකි බලාපොරොත්තුව.
ටොං

68
echo "bla@some.com;john@home.com" | sed -e 's/;/\n/g'
bla@some.com
john@home.com

4
-1 නූලට අවකාශයක් තිබේ නම් කුමක් කළ යුතුද? උදාහරණයක් ලෙස IN="this is first line; this is second line" arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )මෙම නඩුවේ මූලද්‍රව්‍ය 8 ක් (එක් එක් වචන අවකාශය සඳහා වෙන් කරන ලද මූලද්‍රව්‍යයක්) 2 ට වඩා නිපදවනු ඇත (එක් එක් පේළියේ අර්ධ කොලන් වෙන් කරන ලද මූලද්‍රව්‍යයක්)
ලූකා බෝරියන්

3
Uc ලූකා නැත sed ස්ක්‍රිප්ට් හරියටම පේළි දෙකක් නිර්මාණය කරයි. ඔබ සඳහා බහු ඇතුළත් කිරීම් නිර්මාණය කරන්නේ ඔබ එය
බාෂ්

එය හරියටම කාරණයයි: OP ට ඔහුගේ සංස්කරණයන්හි දැකිය හැකි පරිදි, එය හරහා ලූපයක් තැබීම සඳහා අරාවකට ඇතුල් කළ යුතුය. මම හිතන්නේ ඔබේ (හොඳ) පිළිතුර arrIN=( $( echo "$IN" | sed -e 's/;/\n/g' ) )එය සාක්ෂාත් කර ගැනීම සඳහා භාවිතා කිරීම ගැන සඳහන් කිරීම IFS=$'\n'සහ අනාගතයේ දී මෙහි ගොඩබසින අයට අවකාශය සහිත නූලක් බෙදීමට අවශ්‍ය අයට IFS වෙනස් කිරීමට උපදෙස් දීම මග හැරී ඇත . (පසුව එය නැවත පිහිටුවීමට). :)
ලූකා බෝරියන්

1
Uc ලූකා හොඳ කරුණක්. කෙසේ වෙතත්, මම එම පිළිතුර ලියන විට අරාව පැවරුම ආරම්භක ප්‍රශ්නයේ නොවීය.
lothar

66

මෙයද ක්‍රියාත්මක වේ:

IN="bla@some.com;john@home.com"
echo ADD1=`echo $IN | cut -d \; -f 1`
echo ADD2=`echo $IN | cut -d \; -f 2`

ප්රවේශම් වන්න, මෙම විසඳුම සෑම විටම නිවැරදි නොවේ. ඔබ "bla@some.com" පමණක් සමත් වුවහොත් එය එය ADD1 සහ ADD2 යන දෙකටම පවරනු ඇත.


1
සඳහන් කළ ගැටළුව මඟහරවා ගැනීම සඳහා ඔබට -s භාවිතා කළ හැකිය: superuser.com/questions/896800/… "-f, --fields = LIST මෙම ක්ෂේත්‍ර පමණක් තෝරන්න; -s විකල්පය හැර නිශ්චිතව දක්වා ඇත
fersarr

35

ඩැරන්ගේ පිළිතුර වෙනස් ආකාරයකට ගත් විට , මම එය කරන්නේ මෙයයි:

IN="bla@some.com;john@home.com"
read ADDR1 ADDR2 <<<$(IFS=";"; echo $IN)

මම හිතන්නේ ඒක එහෙමයි! ඉහත විධානයන් ක්‍රියාත්මක කර "echo $ ADDR1 ... $ ADDR2" සහ මට "bla@some.com ... john@home.com" ප්‍රතිදානය ලැබේ
nickjb

1
මෙය මට ඉතා හොඳින් ක්‍රියාත්මක විය ... මයිස්ක්ඩම්ප් භාවිතා කිරීම සඳහා කොමා වලින් වෙන් කරන ලද ඩීබී, සර්වර්, පෝර්ට් දත්ත අඩංගු නූල් රාශියක් නැවත සැකසීමට මම එය භාවිතා කළෙමි.
නික්

5
රෝග විනිශ්චය: IFS=";"පැවරුම පවතින්නේ උප කුලකයේ පමණි $(...; echo $IN); සමහර පා readers කයින් (මා ද ඇතුළුව) මුලදී සිතන්නේ එය ක්‍රියාත්මක නොවනු ඇති බවයි. මම උපකල්පනය කළේ AD IN සියල්ලම ADDR1 මගින් ගිලිහී යන බවයි. නමුත් nickjb නිවැරදි ය; එය ක්‍රියාත්මක වේ. හේතුව, echo $INcommand IFS හි වර්තමාන අගය භාවිතා කරමින් විධානය එහි තර්ක විග්‍රහ කරන නමුත් $ IFS සැකසුම නොසලකා අභ්‍යවකාශ පරිසීමකය භාවිතා කරමින් ඒවා ප්‍රතිරාවය කරයි. එබැවින් ශුද්ධ ආචරණය යමෙකු ඇමතූ ආකාරයට ය read ADDR1 ADDR2 <<< "bla@some.com john@home.com"(ආදානය අවකාශයෙන් වෙන් වී නැති බව සලකන්න; වෙන්කර ඇත).
dubiousjim

1
මෙම ස්ථාන සහ හිස් පේලි ගැන මත අසමත්, ද මෙය ආදේශක පුළුල් *තුළ echo $INවූ ලැයිස්තුගත ෙනොකළ විචල්ය පුළුල් වීමත් සමග.
අයිසැක්

මම ඇත්තටම මෙම විසඳුමට කැමතියි. එය ක්‍රියාත්මක වන්නේ ඇයිද යන්න පිළිබඳ විස්තරයක් ඉතා ප්‍රයෝජනවත් වන අතර එය වඩා හොඳ සමස්ත පිළිතුරක් වනු ඇත.
මයිකල් ගැස්කිල්

32

ඔබේ විචල්‍යයේ නව රේඛා තිබුණත්, වෙඩි නොවදින ක්‍රමයක් වන බාෂ් හි එය ක්‍රියාත්මක වේ:

IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")

බලන්න:

$ in=$'one;two three;*;there is\na newline\nin this field'
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two three" [2]="*" [3]="there is
a newline
in this field")'

මෙය ක්‍රියාත්මක කිරීම සඳහා වූ උපක්‍රමය නම් හිස් පරිසීමකය සමඟ (පරිසීමකය) -dවිකල්පය භාවිතා කිරීමයි read, එමඟින් readඑය පෝෂණය කරන සෑම දෙයක්ම කියවීමට බල කෙරෙයි. තවද අපි readවිචල්යයේ අන්තර්ගතය සමඟ පෝෂණය වන අතර in, නව රේඛාවකට ස්තූතිවන්ත නොවෙමු printf. අප විසින් පරිසීමකය දමන බව සලකන්න, printfසම්මත කරන readලද නූලට පසුපස පරිසීමකයක් ඇති බව සහතික කිරීම . එය නොමැතිව, readහිස් පසුපස ඇති විභව ක්ෂේත්‍රයන් කපා දමනු ඇත:

$ in='one;two;three;'    # there's an empty field
$ IFS=';' read -d '' -ra array < <(printf '%s;\0' "$in")
$ declare -p array
declare -a array='([0]="one" [1]="two" [2]="three" [3]="")'

පසුපස හිස් ක්ෂේත්‍රය ආරක්ෂා වේ.


Bash≥4.4 සඳහා යාවත්කාලීන කරන්න

Bash 4.4 සිට, බිල්ඩින් mapfile(අකා readarray) -dපරිසීමකය නියම කිරීමේ විකල්පයට සහය දක්වයි . එබැවින් තවත් කැනොනිකල් ක්‍රමයක් නම්:

mapfile -d ';' -t array < <(printf '%s;' "$in")

5
එම ලැයිස්තුවේ ඇති \nඅවකාශයන් හා *එකවර නිවැරදිව ක්‍රියා කරන දුර්ලභ විසඳුම ලෙස මම එය සොයා ගතිමි . එසේම, ලූප නොමැත; අරා විචල්‍යය ක්‍රියාත්මක කිරීමෙන් පසු කවචයට ප්‍රවේශ විය හැකිය (ඉහළම උඩුකුරු පිළිතුරට පටහැනිව). සටහන, in=$'...'එය ද්විත්ව උපුටා දැක්වීම් සමඟ ක්‍රියා නොකරයි. මම හිතන්නේ, එයට වැඩි දියුණුවක් අවශ්‍යයි.
ජෝන්_වෙස්ට්

29

ඔබ අරා භාවිතා නොකරන්නේ නම් මෙම එක් ලයිනර් ගැන කුමක් කිව හැකිද:

IFS=';' read ADDR1 ADDR2 <<<$IN

read -r ...නිදසුනක් ලෙස, ආදානයේ "\ t" අක්ෂර දෙක ඔබේ විචල්‍යයන්හි එකම අක්ෂර දෙක ලෙස අවසන් වන බව සහතික කිරීම සඳහා භාවිතා කිරීම සලකා බලන්න (තනි ටැබ් ප්‍රස්ථාරයක් වෙනුවට).
dubiousjim

-1 මෙය මෙහි ක්‍රියාත්මක නොවේ (උබුන්ටු 12.04). echo "ADDR1 $ADDR1"\n echo "ADDR2 $ADDR2"ඔබගේ ADDR1 bla@some.com john@home.com\nADDR2
ස්නිපටයට

මෙයට බොහෝදුරට හේතු වී ඇත්තේ 4.3 IFSහි සවි කර ඇති නූල් සම්බන්ධ දෝෂයකි bash. උපුටා දැක්වීම $INඑය නිවැරදි කළ යුතුය. (න්යාය තුල, $INවාර්තා හා ස්ථාවර කිරීමට නියමිත - - දේහය හොඳ උපුටා දක්වමින් එසේ නොවේ වචනය පැලෙන හෝ globbing යටත් තේරුම මේ ආකාරයටම අනවශ්ය විය යුතු, පුළුල් කිරීමෙන් පසුව පවා 4.3 දී, නමුත්, අවම වශයෙන් එක් දෝෂයක් ඉතිරි නැති එක විතරයි. අදහස.)
චෙප්නර්

Line IN උපුටා දැක්වුවද new in නව රේඛා අඩංගු නම් මෙය කැඩී යයි. පසුපස නව රේඛාවක් එක් කරයි.
අයිසැක්

මෙහි ඇති ගැටළුවක් වන අතර තවත් බොහෝ විසඳුම් වන්නේ $ IN - හි හරියටම දෙවරක් මූලද්‍රව්‍ය ඇති බව උපකල්පනය කිරීමයි. එසේත් නැතිනම් ADDR2 හි දෙවන හා පසුව ඇති අයිතම එකට කඩා දැමීමට ඔබ කැමති බව ය. මට තේරෙනවා මේක ඉල්ලීම සපුරාලන නමුත් එය කාල බෝම්බයක්.
ස්ටීවන් පහසුවෙන් විනෝද විය


20

මෙන්න පිරිසිදු 3-ලයිනර්:

in="foo@bar;bizz@buzz;fizz@buzz;buzz@woof"
IFS=';' list=($in)
for item in "${list[@]}"; do echo $item; done

එහිදී IFSdelimit වචන වෙන්කර මත පදනම් ()නිර්මාණය කිරීමට භාවිතා කරයි මාලාවක් . ඉන්පසු [@]සෑම අයිතමයක්ම වෙනම වචනයක් ලෙස ආපසු ලබා දීමට භාවිතා කරයි.

ඊට පසු ඔබට කිසියම් කේතයක් තිබේ නම්, ඔබ ද ප්‍රතිස්ථාපනය කළ යුතුය $IFS, උදා unset IFS.


5
$inනොකැඩූ භාවිතය මඟින් ආදේශක කාඩ්පත් පුළුල් කිරීමට ඉඩ ලබා දේ.
අයිසැක්

10

පහත දැක්වෙන Bash / zsh ශ්‍රිතය දෙවන තර්කය මඟින් ලබා දෙන පරිසීමකය මත එහි පළමු තර්කය බෙදයි:

split() {
    local string="$1"
    local delimiter="$2"
    if [ -n "$string" ]; then
        local part
        while read -d "$delimiter" part; do
            echo $part
        done <<< "$string"
        echo $part
    fi
}

උදාහරණයක් ලෙස, විධානය

$ split 'a;b;c' ';'

අස්වැන්න

a
b
c

නිදසුනක් ලෙස, මෙම ප්‍රතිදානය වෙනත් විධානයන් වෙත යොමු කළ හැකිය. උදාහරණයක්:

$ split 'a;b;c' ';' | cat -n
1   a
2   b
3   c

ලබා දී ඇති අනෙක් විසඳුම් හා සසඳන විට, පහත සඳහන් වාසි ඇත:

  • IFSඅතිච්ඡාදනය නොවේ: දේශීය විචල්‍යයන් පවා ගතිකව පරික්ෂා කිරීම හේතුවෙන්, IFSලූපයක් ඉක්මවා යාමෙන් නව අගය ලූපය තුළ සිට සිදුකරන ශ්‍රිත ඇමතුම් වලට කාන්දු වේ.

  • අරා භාවිතා නොකෙරේ: අරාව තුළට නූලක් කියවීමට Bash සහ zsh හි readධජය අවශ්‍ය වේ .-a-A

අවශ්‍ය නම්, ශ්‍රිතය පහත පරිදි ස්ක්‍රිප්ටයකට දැමිය හැකිය:

#!/usr/bin/env bash

split() {
    # ...
}

split "$@"

අක්ෂර 1 ට වඩා දිග පරිසීමකයන් සමඟ වැඩ කරන බවක් නොපෙනේ: split = $ (බෙදීම "$ අන්තර්ගතය" "ගොනුව: //")
පිස්සු හැදීම්

ඇත්ත - සිට help read:-d delim continue until the first character of DELIM is read, rather than newline
හැලේ නස්ට්

8

ඔබට බොහෝ අවස්ථාවන්ට අවදි විය හැකිය

echo "bla@some.com;john@home.com"|awk -F';' '{printf "%s\n%s\n", $1, $2}'

ඔබට මෙය භාවිතා කළ හැකිය

echo "bla@some.com;john@home.com"|awk -F';' '{print $1,$2}' OFS="\n"

7

මේ වගේ සරල හා බුද්ධිමත් ක්‍රමයක් තිබේ:

echo "add:sfff" | xargs -d: -i  echo {}

නමුත් ඔබ gnu xargs භාවිතා කළ යුතුය, BSD xargs cant support -d delim. ඔබ මා වැනි ඇපල් මැක් භාවිතා කරන්නේ නම්. ඔබට gnu xargs ස්ථාපනය කළ හැකිය:

brew install findutils

එවිට

echo "add:sfff" | gxargs -d: -i  echo {}

4

මෙය කළ හැකි සරලම ක්‍රමය මෙයයි.

spo='one;two;three'
OIFS=$IFS
IFS=';'
spo_array=($spo)
IFS=$OIFS
echo ${spo_array[*]}

4

මෙහි සිසිල් පිළිතුරු කිහිපයක් ඇත (errator esp.), නමුත් වෙනත් භාෂාවලට බෙදීමට සමාන යමක් සඳහා - එහි මුල් ප්‍රශ්නය මා අදහස් කළේ එයයි - මම මේ පිළිබඳව සමථයකට පත් කළෙමි:

IN="bla@some.com;john@home.com"
declare -a a="(${IN/;/ })";

දැන් ${a[0]}, ${a[1]}ආදිය, ඔබ අපේක්ෂා කළ පරිදි ය. ${#a[*]}පද ගණනක් සඳහා භාවිතා කරන්න . නැතහොත් නැවත කියවීමට:

for i in ${a[*]}; do echo $i; done

වැදගත් සටහනක්:

කනස්සල්ලට පත්වීමට ඉඩක් නොමැති අවස්ථාවන්හිදී මෙය ක්‍රියාත්මක වන අතර එය මගේ ගැටලුව විසඳූ නමුත් ඔබේ ගැටලුව විසඳන්නේ නැත. $IFSඑම අවස්ථාවේ දී විසඳුම (ය) සමඟ යන්න .


INවිද්‍යුත් තැපැල් ලිපින දෙකකට වඩා ඇති විට ක්‍රියා නොකරයි .
පාලින්ඩ්‍රෝම්ගේ

${IN//;/ }එය අගයන් දෙකකට වඩා වැඩ කිරීමට වඩා හොඳ භාවිතය (ද්විත්ව කප්පාදුව). ඕනෑම ආදේශක කාඩ්පතක් ( *?[) පුළුල් වන බවට පරිස්සම් වන්න . පසුපස හිස් ක්ෂේත්‍රයක් ඉවතලනු ලැබේ.
අයිසැක්

3
IN="bla@some.com;john@home.com"
IFS=';'
read -a IN_arr <<< "${IN}"
for entry in "${IN_arr[@]}"
do
    echo $entry
done

ප්‍රතිදානය

bla@some.com
john@home.com

පද්ධතිය: උබුන්ටු 12.04.1


readමෙහි නිශ්චිත සන්දර්භය තුළ අයිඑෆ්එස් සැකසෙන්නේ නැති අතර එමඟින් ඉතිරි කේත තිබේ නම් එය අවුල් කළ හැකිය.
codeforester

2

ඉඩක් නැත්නම්, ඇයි මේ?

IN="bla@some.com;john@home.com"
arr=(`echo $IN | tr ';' ' '`)

echo ${arr[0]}
echo ${arr[1]}

2

අරාව setපූරණය කිරීම සඳහා සාදන ලද භාවිතා කරන්න $@:

IN="bla@some.com;john@home.com"
IFS=';'; set $IN; IFS=$' \t\n'

එවිට, පක්ෂය ආරම්භ කිරීමට ඉඩ දෙන්න:

echo $#
for a; do echo $a; done
ADDR1=$1 ADDR2=$2

ඉරකින් set -- $INආරම්භ වන "$ IN" සමඟ ඇති සමහර ගැටළු වළක්වා ගැනීමට වඩා හොඳ භාවිතය . තවමත්, නොකියවූ ව්‍යාප්තිය $INමගින් ආදේශක කාඩ්පත් පුළුල් වනු ඇත ( *?[).
අයිසැක්

2

බාෂ් අරා අවශ්‍ය නොවන බෝර්න්-ඊෂ් විකල්ප දෙකක්:

1 වන අවස්ථාව : එය ලස්සන හා සරල ලෙස තබා ගන්න: රෙකෝඩ්-බෙදුම්කරු ලෙස නිව්ලයින් භාවිතා කරන්න ... උදා.

IN="bla@some.com
john@home.com"

while read i; do
  # process "$i" ... eg.
    echo "[email:$i]"
done <<< "$IN"

සටහන: මෙම පළමු අවස්ථාවෙහිදී ලැයිස්තු හැසිරවීමට සහාය වීම සඳහා කිසිදු උප ක්‍රියාවලියක් බල නොකෙරේ.

අදහස: සමහර විට එය අභ්‍යන්තරව එන්එල් භාවිතා කිරීම වටී , අවසාන ප්‍රති result ලය බාහිරව ජනනය කිරීමේදී පමණක් වෙනත් ආර්එස් වෙත පරිවර්තනය කිරීම පමණි .

2 වන අවස්ථාව : ";" වාර්තා බෙදුම්කරුවෙකු ලෙස ... උදා.

NL="
" IRS=";" ORS=";"

conv_IRS() {
  exec tr "$1" "$NL"
}

conv_ORS() {
  exec tr "$NL" "$1"
}

IN="bla@some.com;john@home.com"
IN="$(conv_IRS ";" <<< "$IN")"

while read i; do
  # process "$i" ... eg.
    echo -n "[email:$i]$ORS"
done <<< "$IN"

අවස්ථා දෙකේදීම ලූපය තුළ උප ලැයිස්තුවක් රචනා කළ හැකිය. මතකයේ ලැයිස්තු හැසිරවීමේදී මෙය ප්‍රයෝජනවත් වේ, ඒ වෙනුවට ලිපිගොනු වල ගොනු ගබඩා කරයි. {ps සන්සුන්ව සිට B- ඉදිරියට යන්න)}


2

දැනටමත් ලබා දී ඇති අපූරු පිළිතුරු හැරුණු විට, එය භාවිතා කිරීම සඳහා ඔබ සලකා බැලිය හැකි දත්ත මුද්‍රණය කිරීම පමණක් නම් awk:

awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"

මෙමඟින් ක්ෂේත්‍ර බෙදුම්කරු සකසා ඇති අතර එමඟින් ක්ෂේත්‍ර ;හරහා forලූපයකින් ලූපයක් තබා ඒ අනුව මුද්‍රණය කළ හැකිය.

පරීක්ෂණය

$ IN="bla@some.com;john@home.com"
$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "$IN"
> [bla@some.com]
> [john@home.com]

වෙනත් ආදානයක් සමඟ:

$ awk -F";" '{for (i=1;i<=NF;i++) printf("> [%s]\n", $i)}' <<< "a;b;c   d;e_;f"
> [a]
> [b]
> [c   d]
> [e_]
> [f]

2

ඇන්ඩ්‍රොයිඩ් කවචයේ, යෝජිත ක්‍රම බොහොමයක් ක්‍රියා නොකරයි:

$ IFS=':' read -ra ADDR <<<"$PATH"                             
/system/bin/sh: can't create temporary file /sqlite_stmt_journals/mksh.EbNoR10629: No such file or directory

වැඩ කරන්නේ කුමක්ද:

$ for i in ${PATH//:/ }; do echo $i; done
/sbin
/vendor/bin
/system/sbin
/system/bin
/system/xbin

එහිදී //ගෝලීය වෙනුවට බවයි.


1
AT PATH හි කිසියම් කොටසක අවකාශයන් (හෝ නව රේඛා) තිබේ නම් අසමත් වේ. ආදේශක කාඩ්පත් (තරු ලකුණු *, ප්‍රශ්නාර්ථ ලකුණ සහ වරහන් […]) පුළුල් කරයි.
අයිසැක්

2
IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'
set -f
oldifs="$IFS"
IFS=';'; arrayIN=($IN)
IFS="$oldifs"
for i in "${arrayIN[@]}"; do
echo "$i"
done
set +f

ප්‍රතිදානය:

bla@some.com
john@home.com
Charlie Brown <cbrown@acme.com
!"#$%&/()[]{}*? are no problem
simple is beautiful :-)

පැහැදිලි කිරීම: වරහන් () භාවිතා කරමින් සරල පැවරුමක් මඟින් අර්ධ සළකුණු වෙන් කළ ලැයිස්තුව අරාව බවට පරිවර්තනය කරයි. ස්ටෑන්ඩර්ඩ් ෆෝ ලූප් සුපුරුදු පරිදි එම අරාවෙහි ඇති තනි අයිතම හසුරුවයි. IN විචල්‍යය සඳහා ලබා දී ඇති ලැයිස්තුව “දෘඩ” ලෙස උපුටා දැක්විය යුතු බව සලකන්න, එනම් තනි කිනිතුල්ලන් සමඟ.

පැවරුමක් විධානයක් ලෙස Bash නොසලකන බැවින් IFS සුරැකිය යුතු අතර ප්‍රතිෂ් ored ාපනය කළ යුතුය. විකල්ප කාර්යයක් නම්, පැවරුම ශ්‍රිතයක් තුළට ඔතා එම ශ්‍රිතය නවීකරණය කරන ලද IFS සමඟ අමතන්න. එවැනි අවස්ථාවකදී IFS හි වෙනම ඉතිරිකිරීම / ප්‍රතිස්ථාපනය අවශ්‍ය නොවේ. එය පෙන්වා දීම ගැන "බයිස්" ට ස්තූතියි.


!"#$%&/()[]{}*? are no problemහොඳයි ... එතරම් නොවේ: []*?ගෝලීය අක්ෂර වේ. ඉතින් මෙම ඩිරෙක්ටරිය සහ ගොනුව නිර්මාණය කිරීම ගැන කුමක් කිව හැකිද: `mkdir '!" # $% &'; ස්පර්ශ කරන්න! " සරල ලස්සන විය හැකි නමුත් එය කැඩී ගිය විට එය කැඩී ඇත.
gniourf_gniourf

stringniourf_gniourf නූල විචල්යයක ගබඩා කර ඇත. කරුණාකර මුල් ප්‍රශ්නය බලන්න.
ajaaskel

1
jajaaskel ඔබට මගේ අදහස සම්පූර්ණයෙන්ම තේරුණේ නැත. සීරීම් නාමාවලියකට ගොස් මෙම විධානයන් නිකුත් කරන්න : mkdir '!"#$%&'; touch '!"#$%&/()[]{} got you hahahaha - are no problem'. ඔවුන් ඩිරෙක්ටරියක් සහ ගොනුවක් පමණක් නිර්මාණය කරනු ඇත, අමුතු පෙනුමක් ඇති නම්, මම පිළිගත යුතුය. ඉන්පසු INඔබ දුන් හරියටම ඔබේ විධානයන් ක්‍රියාත්මක කරන්න : IN='bla@some.com;john@home.com;Charlie Brown <cbrown@acme.com;!"#$%&/()[]{}*? are no problem;simple is beautiful :-)'. ඔබ අපේක්ෂා කරන ප්‍රතිදානය ඔබට නොලැබෙන බව ඔබට පෙනෙනු ඇත. මන්දයත් ඔබ ඔබේ නූල බෙදීමට මාර්ග නාම පුළුල් කිරීම් වලට යටත්ව ක්‍රමයක් භාවිතා කරන බැවිනි.
gniourf_gniourf

මෙම චරිත බව පැහැදිලි කිරීමට ය *, ?, [...]පවා, නම් extglobකර ඇත, !(...), @(...), ?(...), +(...) වේ ගැටලු මෙම ක්රමය සමග!
gniourf_gniourf

1
@gniourf_gniourf ගෝලීයකරණය පිළිබඳ සවිස්තරාත්මක අදහස් දැක්වීම් වලට ස්තූතියි. මම කේතය සකස් කළේ ග්ලෝබල් කිරීම නතර කිරීමටයි. කෙසේ වෙතත් මගේ අදහස වූයේ සරල පැවරුමකට බෙදීමේ කාර්යය කළ හැකි බව පෙන්වීම පමණි.
ajaaskel

1

හරි යාලුවනේ!

මෙන්න මගේ පිළිතුර!

DELIMITER_VAL='='

read -d '' F_ABOUT_DISTRO_R <<"EOF"
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.4 LTS"
NAME="Ubuntu"
VERSION="14.04.4 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.4 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
EOF

SPLIT_NOW=$(awk -F$DELIMITER_VAL '{for(i=1;i<=NF;i++){printf "%s\n", $i}}' <<<"${F_ABOUT_DISTRO_R}")
while read -r line; do
   SPLIT+=("$line")
done <<< "$SPLIT_NOW"
for i in "${SPLIT[@]}"; do
    echo "$i"
done

මෙම ප්‍රවේශය මට "හොඳම" වන්නේ ඇයි?

හේතු දෙකක් නිසා:

  1. පරිසීමාවෙන් ගැලවීමට ඔබට අවශ්‍ය නැත ;
  2. හිස් අවකාශයන් සමඟ ඔබට ගැටළුවක් ඇති නොවේ . අරාව තුළ අගය නිසි ලෙස වෙන් කරනු ඇත!

[] ගේ


FYI, /etc/os-releaseසහ /etc/lsb-releaseඒවා උපුටා ගැනීමට අදහස් කරන අතර විග්‍රහ නොකෙරේ. එබැවින් ඔබේ ක්‍රමය ඇත්තෙන්ම වැරදිය. එපමණක් නොව, පරිසීමකය මත නූලක් විදීම
gniourf_gniourf

0

';' මගින් වෙන් කරන ලද නූලක් බෙදීමට එක් ලයිනර්. අරාවකට:

IN="bla@some.com;john@home.com"
ADDRS=( $(IFS=";" echo "$IN") )
echo ${ADDRS[0]}
echo ${ADDRS[1]}

මෙය IFS උපසිරැසියක පමණක් සකසයි, එබැවින් එහි වටිනාකම සුරැකීම සහ ප්‍රතිෂ් oring ාපනය කිරීම ගැන ඔබට කරදර විය යුතු නැත.


-1 මෙය මෙහි ක්‍රියාත්මක නොවේ (උබුන්ටු 12.04). එය මුද්‍රණය කරන්නේ එහි සියලු $ IN අගය සහිත පළමු දෝංකාරය පමණක් වන අතර දෙවැන්න හිස් ය. ඔබ දෝංකාරය තැබුවහොත් ඔබට එය දැක ගත හැකිය "0:" $ {ADDRS [0] echo \ n echo "1:" $ {ADDRS [1]} ප්‍රතිදානය 0: bla@some.com;john@home.com\n 1:(new n නව රේඛාවකි)
ලූකා බෝරියන්

1
කරුණාකර මෙම අදහසට ක්‍රියාකාරී විකල්පයක් සඳහා නික්ජ්ගේ පිළිතුර යොමු කරන්න stackoverflow.com/a/6583589/1032370
Luca Borrione

1
-1, 1. එම උප කුලකයේ IFS සකසා නොමැත (එය "echo" හි පරිසරයට යවනු ලැබේ, එය ගොඩනඟන ලද්දකි, එබැවින් කිසිවක් සිදුවන්නේ නැත). 2. $INඋපුටා දක්වා ඇති බැවින් එය IFS බෙදීමට යටත් නොවේ. 3. ක්‍රියාවලි ආදේශනය සුදු අවකාශයෙන් බෙදී ඇති නමුත් මෙය මුල් දත්ත දූෂිත කළ හැකිය.
ලකුණු_අන්ඩර්

0

සමහර විට වඩාත්ම අලංකාර විසඳුම නොව, *සහ අවකාශයන් සමඟ ක්‍රියා කරයි :

IN="bla@so me.com;*;john@home.com"
for i in `delims=${IN//[^;]}; seq 1 $((${#delims} + 1))`
do
   echo "> [`echo $IN | cut -d';' -f$i`]"
done

නිමැවුම්

> [bla@so me.com]
> [*]
> [john@home.com]

වෙනත් උදාහරණය (ආරම්භයේ සහ අවසානයේ ඇති පරිසීමක):

IN=";bla@so me.com;*;john@home.com;"
> []
> [bla@so me.com]
> [*]
> [john@home.com]
> []

මූලික වශයෙන් එය උදා ;කිරීම හැර අනෙක් සෑම චරිතයක්ම ඉවත් කරයි delims. ;;;. එවිට එය forසිට පුඩුවක් 1කිරීමට number-of-delimitersවිසින් ගණන් ලෙස ${#delims}. අවසාන පියවර වන්නේ තෙවන $iකොටස ආරක්ෂිතව ලබා ගැනීමයි cut.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.