it-swarm-eu.dev

Jak vložit obsah souboru do jiného souboru před vzorem (značkou)?

File1 obsah:

line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 

File2 obsah:

line1-file2     "25"  
line2-file2     "24"  
Pointer-file2   "23"  
line4-file2     "22" 
line5-file2     "21"

Po spuštění skriptu Perl/Shell, File2 obsah by se měl stát:

line1-file2     "25"  
line2-file2     "24" 
line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 
Pointer-file2   "23" 
line4-file2     "22" 
line5-file2     "21"

tj. vložte obsah File1 v File2 před řádek, který obsahuje „Ukazatel“.

39
user1228191

sed má k tomu funkci a může provádět úpravy inline:

sed -i -e '/Pointer/r file1' file2

Tím se však váš řádek umístí nad soubor1. Chcete-li ji umístit níže, zpoždění řádku výstup:

sed -n -i -e '/Pointer/r file1' -e 1x -e '2,${x;p}' -e '${x;p}' file2 


S GNU sed

sed '/Pointer/e cat file1' file2

Podle manuálně pro e [command]

Všimněte si, že na rozdíl od příkazu r bude výstup příkazu vytištěn okamžitě; příkaz r místo toho zpožďuje výstup do konce aktuálního cyklu.

37
jfg956

Bez použití sed nebo awk...

Nejprve najděte linii, na které je váš vzor:

line=$(grep -n 'Pointer' file2 | cut -d ":" -f 1)

Poté použijte 3 příkazy k výstupu požadovaného výsledku:

{ head -n $(($line-1)) file2; cat file1; tail -n +$line file2; } > new_file

To má tu nevýhodu, že k souboru 3krát přistupujete file2, ale může být jasnější než řešení sed of awk.

18
jfg956

awk to značně usnadňuje.
Vložte řádek před soubor:

awk '/Pointer/{while(getline line<"innerfile"){print line}} //' outerfile >tmp
mv tmp outerfile

Chcete-li, aby se vnitřní soubor tiskl za řádkem Pointer, stačí změnit pořadí vzorů (pro získání výchozí akce je třeba přidat středník) a můžete vypustit proměnnou line:

awk '//; /Pointer/{while(getline<"innerfile"){print}}' outerfile >tmp
mv tmp outerfile

A jen proto, že ještě nikdo nepoužil Perl,

# insert file before line
Perl -e 'while(<>){if($_=~/Pointer/){system("cat innerfile")};print}' outerfile

# after line
Perl -e 'while(<>){print;if($_=~/Pointer/){system("cat innerfile")}}' outerfile
11
Kevin

Snadná úloha pro ed:

ed -s file1 <<IN
/Pointer/-r file2
,p
q
IN

-r file1 přečte v zadaném souboru až za adresovaný řádek, což je v tomto případě řádek předcházející prvnímu řádku odpovídajícímu Pointer. Vloží se tedy obsah file2 pouze jednou, i když Pointer se vyskytuje na více řádcích. Pokud jej chcete vložit před každý odpovídající řádek, přidejte g lobal příznak:

ed -s file1 <<IN
g/Pointer/-r file2
,p
q
IN

Nahradit ,p s w, pokud chcete soubor upravit na místě.


Přijatá odpověď sed funguje ve většině případů, ale pokud je značka na posledním řádku, příkaz nebude fungovat podle očekávání: vloží obsah File1 za značku.
Původně jsem se pokusil:

sed '/Pointer/{r file1
N}' file2

což také funguje dobře (protože r udělá svou magii na konci cyklu), ale má stejný problém, pokud je značka na posledním řádku (po posledním řádku není žádný řádek N ext) řádek). Chcete-li tento problém vyřešit, můžete do svého vstupu přidat nový řádek:

sed '/Pointer/{              # like the first one, but this time even if the
r file1                      # marker is on the last line in File2 it
N                            # will be on the second to last line in
}                            # the combined input so N will always work;
${                           # on the last line of input: if the line is
/^$/!{                       # not empty, it means the marker was on the last
s/\n$//                      # line in File2 so the final empty line in the
}                            # input was pulled i\n: remove the latter;
//d                          # if the line is empty, delete it
}' file2 <(printf %s\\n)

Tím vložíte file2 obsah před každým odpovídajícím řádkem. Chcete-li jej vložit pouze před první odpovídající řádek, můžete použít oop l a jednoduše vytáhnout řádek extenze n, dokud se nedostanete na konec souboru:

sed '/Pointer/{
r file2
N
:l
$!n
$!bl
}
${
/^$/!{
s/\n$//
}
//d
}' file1 <(printf %s\\n)

S těmito řešeními sed ztratíte možnost úpravy na místě (můžete však přesměrovat na jiný soubor).

7
don_crissti

K načtení řádků v souboru2 použijte smyčku. Pokud najdete řádek začínající na Pointer, vytiskněte soubor1. Toto je zobrazeno níže:

#!/bin/bash
while IFS= read -r line
do
    if [[ "$line" =~ ^Pointer.*$ ]]
    then
        cat file1
    fi
    echo "$line"
done < file2
6
dogbane

Existuje několik způsobů, jak to udělat w/sed. Jedním ze způsobů je odložené čtení, jak je doporučeno v přijaté odpovědi. Mohlo by to být také psáno jako:

sed -e '$!N;P;/\nPointer/r file1' -e D file2

... s trochou explicitního pohledu dopředu namísto pohledu implementovaného jinde s vyrovnávací pamětí hold. To bude nevyhnutelně mít stejný problém s posledním řádkem, který si všimne @don_crissti, protože N dělá zvyšuje řádkový cyklus a příkaz read se používá podle čísla řádku.

Můžete to obejít:

echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -

Ne všechny seds interpretují - znamená standardní vstup, ale mnoho ano. ( říká POSIXsed by měla podporovat - znamená standardní vstup, pokud implementátor chce - znamená standardní vstup ???)

Dalším způsobem je zpracování připojeného obsahu v pořádku. Existuje další příkaz, který plány výstup stejným způsobem read provede, a sed použije a read v aby byly skripty. Je to ale trochu více zapojeno - vyžaduje to použití jednoho sedappendování Pointer shody s výstupem jiného sed ve skriptu .

sed '   /Pointer/!d                  #only operate on first match
        s/[]^$&\./*[]/\\&/g;H        #escape all metachars, Hold
        s|.*|/&/!p;//!d|p;g          #print commands, exchange
        s|.|r file1&a\\&|;q' file2|  #more commands, quit
        sed -nf - file2              #same input file

Takže první sed v podstatě zapisuje druhý sed skript, který druhý sed čte na standard-input (možná ...) a platí postupně. První sed funguje pouze pro první shodu pro Pointer nalezené a poté quits vstup. Jeho úkolem je ...

  1. s/[]^$&\./*[]/\\&/g;H
    • Ujistěte se, že všechny znakové znaky jsou bezpečně uniknuty zpětným lomítkem, protože druhý sed bude muset interpretovat každý bit, který přečte, doslova, aby to bylo správné. Po dokončení vložte kopii do Hold prostoru.
  2. s|.*|/&/!p;//!d|p; x
    • Řekněte druhé sed to print každý vstupní řádek !ale /&/ jeden, který jsme právě zabezpečili; a potom delete všechny stejné. pzadejte příkazy na druhém sed, poté exzměňte hold a vzorové vyrovnávací paměti, aby pracovaly na naší uložené kopii.
  3. s|.|r file1&a\\&|p;q
    • Jediný znak, se kterým pracujeme, je \newline, protože sed bude mít připravený jeden, když Held line předtím. Vložíme tedy příkaz r file1 a sledujte to s naším \newline, pak příkaz a\\ pro append následované také \newline. Celý zbytek naší Held linie následuje poslední \newline.

Skript, který první píše, vypadá asi takto:

/Pointer-file2   "23"/!p;//!d
r file1
a\
Pointer-file2   "23"

V podstatě druhý sed vytiskne každý řádek, ale ten, který první sed nastaví na append. Pro tento konkrétní řádek dva zpožděné zápisy do standard-out jsou naplánováno - první je read of file1 a druhá je kopie řádku, který chceme po něm. První doktorské sed není v tomto případě vůbec nutné (viz? Žádná zpětná lomítka), ale je důležité bezpečně uniknout tak, jak to dělám, kdykoli se shoduje vzor je znovu použit jako vstup.

Každopádně ... existuje několik způsobů.

4
mikeserv

[Vložte obsah souboru do jiného souboru PŘED vzorem]

sed -i '/PATTERN/r file1' -e //N file2

[Po vzoru]

sed -i '/PATTERN/r file1' file2
3
Jim.Y

můj preferovaný způsob: templating.

sed 's/CHANGEME/$x/g' origfile | x="$(<file2insert)" envsubst '$x' > newfile

Toto nahradí každý výskyt CHANGEME v origfile obsahem file2insert. Odstraňte poslední g ze sedu, abyste nahradili pouze první výskyt CHANGEME .

2
nrc

U AWK je to celkem jednoduché:

File1 do File2 before pattern = "Ukazatel"

Nejprve načtěte obsah File1 do proměnné

f1="$(<File1)"

pak proveďte vložení

awk -vf1="$f1" '/Pointer/{print f1;print;next}1' file2

(Nebo, pokud chcete vložit File1 za „Ukazatel“)

awk -vf1="$f1" '/Pointer/{print;print f1;next}1' file2
2
Amos Folarin
 awk '/Pointer/{system("cat File1")}1' File2
0
dedowsdi