GNU/Linux >> Znalost Linux >  >> Linux

Jak vybrat více řádků ze souboru nebo z potrubí ve skriptu?

Můžete použít tento awk:

awk -v s='2,4' 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' file
two
four

Prostřednictvím samostatného skriptu lines.sh :

#!/bin/bash
awk -v s="$1" 'BEGIN{split(s, a, ","); for (i in a) b[a[i]]} NR in b' "$2"

Poté udělte oprávnění ke spuštění:

chmod +x lines.sh

A nazvěte to jako:

./lines.sh '2,4' 'test.txt'

Zkuste sed :

sed -n '2p; 4p' inputFile

-n říká sed pro potlačení výstupu, ale pro řádky 2 a 4 , p (print) se používá k vytištění těchto řádků.

Můžete také použít rozsahy, např.:

sed -n '2,4p' inputFile

Dvě čisté verze Bash. Vzhledem k tomu, že hledáte obecná a opakovaně použitelná řešení, můžete do toho vložit trochu úsilí. (Viz také poslední část).

Verze 1

Tento skript uspořádá celý stdin do pole (pomocí mapfile , takže je to spíše efektivní) a pak vytiskne řádky uvedené na svých argumentech. Rozsahy jsou platné, např.

1-4 # for lines 1, 2, 3 and 4
3-  # for everything from line 3 till the end of the file

Můžete je oddělit mezerami nebo čárkami. Řádky jsou vytištěny přesně v pořadí, v jakém jsou uvedeny argumenty:

lines 1 1,2,4,1-3,4- 1

vytiskne dvakrát řádek 1, potom řádek 2, potom řádek 4, potom řádky 1, 2 a 3, potom vše od řádku 4 až do konce a nakonec znovu řádek 1.

Tady to je:

#!/bin/bash

lines=()

# Slurp stdin in array
mapfile -O1 -t lines

# Arguments:
IFS=', ' read -ra args <<< "$*"

for arg in "${args[@]}"; do
   if [[ $arg = +([[:digit:]]) ]]; then
      arg=$arg-$arg
   fi
   if [[ $arg =~ ([[:digit:]]+)-([[:digit:]]*) ]]; then
      ((from=10#${BASH_REMATCH[1]}))
      ((to=10#${BASH_REMATCH[2]:-$((${#lines[@]}))}))
      ((from==0)) && from=1
      ((to>=${#lines[@]})) && to=${#lines[@]}
      ((from<=to)) || printf >&2 'Argument %d-%d: lines not in increasing order' "$from" "$to"
      for((i=from;i<=to;++i)); do
         printf '%s\n' "${lines[i]}"
      done
   else
      printf >&2 "Error in argument \`%s'.\n" "$arg"
   fi
done
  • Pro:Je to opravdu skvělé.
  • Con:Potřebuje načíst celý stream do paměti. Nevhodné pro nekonečné proudy.

Verze 2

Tato verze řeší předchozí problém nekonečných proudů. Ale ztratíte možnost opakovat a měnit pořadí řádků.

Totéž, rozsahy jsou povoleny:

lines 1 1,4-6 9-

vytiskne řádky 1, 4, 5, 6, 9 a vše až do konce. Pokud je sada řádků ohraničená, ukončí se, jakmile je přečten poslední řádek.

#!/bin/bash

lines=()
tillend=0
maxline=0

# Process arguments
IFS=', ' read -ra args <<< "[email protected]"

for arg in "${args[@]}"; do
   if [[ $arg = +([[:digit:]]) ]]; then
       arg=$arg-$arg
   fi
   if [[ $arg =~ ([[:digit:]]+)-([[:digit:]]*) ]]; then
      ((from=10#${BASH_REMATCH[1]}))
      ((from==0)) && from=1
      ((tillend && from>=tillend)) && continue
      if [[ -z ${BASH_REMATCH[2]} ]]; then
         tillend=$from
         continue
      fi
      ((to=10#${BASH_REMATCH[2]}))
      if ((from>to)); then
         printf >&2 "Invalid lines order: %s\n" "$arg"
         exit 1
      fi
      ((maxline<to)) && maxline=$to
      for ((i=from;i<=to;++i)); do
         lines[i]=1
      done
   else
      printf >&2 "Invalid argument \`%s'\n" "$arg"
      exit 1
   fi
done

# If nothing to read, exit
((tillend==0 && ${#lines[@]}==0)) && exit

# Now read stdin
linenb=0
while IFS= read -r line; do
   ((++linenb))
   ((tillend==0 && maxline && linenb>maxline)) && exit
   if [[ ${lines[linenb]} ]] || ((tillend && linenb>=tillend)); then
      printf '%s\n' "$line"
   fi
done
  • Pro:Je to opravdu skvělé a nečte celý stream v paměti.
  • Nevýhoda:Nelze opakovat nebo měnit pořadí řádků jako verze 1. Rychlost není její nejsilnější stránkou.

Další myšlenky

Pokud opravdu chcete úžasný obecný skript, který dělá to, co verze 1 a verze 2 a ještě více, rozhodně byste měli zvážit použití jiného jazyka, např. Perl:hodně získáte (zejména rychlost)! budete moci mít pěkné možnosti, které budou dělat spoustu mnohem chladnějších věcí. Z dlouhodobého hlediska by to mohlo stát za to, protože chcete obecný a opakovaně použitelný skript. Můžete dokonce skončit se skriptem, který čte e-maily!

Odmítnutí odpovědnosti. Tyto skripty jsem důkladně nezkontroloval... takže pozor na chyby!


Linux
  1. Jak odstranit prázdné řádky ze souboru (včetně tabulátoru a mezer)?

  2. Jak odstranit více náhodných řádků z textového souboru pomocí Sed?

  3. Jak odstranit řádky, které se objevují v souboru B, z jiného souboru A?

  1. Jak vyberu veškerý text ze souboru s nano?

  2. Jak se install -c liší od cp

  3. Jak zkrátit soubor podle řádků?

  1. Vyberte řádky z textového souboru, jejichž ID jsou uvedena v jiném souboru?

  2. Jak vytvořit dočasný soubor ve skriptu Shell?

  3. Jak vykopat soubor z Awk?