For Loop in Bash Simply Prints N Times the Command Instead of Reiterating

for loop in bash simply prints n times the command instead of reiterating

I think I see what you're after. There are a few problems with your approach:

  • awk doesn't process files in-place. So your sub() makes a change, 1 prints to stdout, but your input file never changes.
  • When you sub(), you don't insert a new record into the input stream that awk is processing. Your command merely adds a newline to the current record.

Given these, you could get away with processing the input multiple times, as you've suggested. But rather than arbitrarily assuming that you'll have a maximum of seven 10-word phrases on a line, it might be better to actually detect whether you need to continue. Something like this:

#!/usr/bin/env bash

input=input.txt
temp=$(mktemp ${input}.XXXX)
trap "rm -f $temp" 0

while awk '
BEGIN { retval=1 }
NF >= 10 && /, / {
sub(/, /, ","ORS)
retval=0
}
1
END { exit retval }
' "$input" > "$temp"; do
mv -v $temp $input
done

This uses an exit value from awk to determine whether we need to run another iteration of the bash loop. If awk detects that no substitutions were required, then the loop stops.

split lines/sentence with over 10 words where the first comma appears

A better approach is to use awk and test for 15 or more words and if so, just substitute a ",\n" for a ", ", e.g.

awk 'NF >= 15 {sub (", ", ",\n")}1' file

Example Use/Output

With your input in file, you would have:

$ awk 'NF >= 15 {sub (", ", ",\n")}1' file
phrase from a test line,
which I want to split, and I don't know how.

(if you have a large number of lines, awk will be orders-of-magnitude faster than a shell loop)

bash find and replace - sed awk

You may always pipe sed commands, but in this case it makes sense to combine all the conditions into one command:

sed 's/[.!?]/&\n/g' file > newfile

The [.!?] matches ., ! or ? and & in the replacement pattern puts the match value back into the string (the newline is added right after this value).

See the online demo:

s="This is a text. Want more? Yes! End"
sed 's/[.!?]/&\n/g' <<< "$s"

Output:

This is a text.
Want more?
Yes!
End

If you need to get rid of the spaces after ?, ! and . use

sed 's/\([.!?]\)[[:space:]]*/\1\n/g' file > newfile

See another sed demo. Here:

  • \([.!?]\) - Capturing group 1: matches ., ! or ?
  • [[:space:]]* - 0 or more whitespaces

The \1 in the replacement pattern refers to the value captured into Group 1.

Repeat each line multiple times by using Linux

In case perl is an option:

perl -ne '@A=split;print "$A[2]\n" x ($A[1]-$A[0])' my_file.txt

For each line, it splits the line on whitespace and @A is the array holding that result.

It then prints the third element in the array ($A[2]) + a newline, repeated (the x) the number of times you have if you take the value in column 2 minus the value in column 1.

How to get the first line of a file in a bash script?

head takes the first lines from a file, and the -n parameter can be used to specify how many lines should be extracted:

line=$(head -n 1 filename)

bash: executing an output of a script as a script

You need to use an eval, $() gives you a string.

eval $( echo echo foo )

Another option is to stick into a subshell and pipe it to a bash:

(echo echo foo) | /bin/bash

What does set -e mean in a bash script?

From help set :

  -e  Exit immediately if a command exits with a non-zero status.

But it's considered bad practice by some (bash FAQ and irc freenode #bash FAQ authors). It's recommended to use:

trap 'do_something' ERR

to run do_something function when errors occur.

See http://mywiki.wooledge.org/BashFAQ/105

Why is this bash while loop infinite?

There are two mistakes in your script:

The first mistake is the broken while clause, it should read

while condition; do
commands
done

or

while condition
do
commands
done

whereas condition might be a test expression that returns zero or non-zero as you correctly wrote:

[ $check -gt 10000 ]

The line

check = $(du -sb /home/chris/Dropbox/VideoMonitor | cut -f1)

before the do is mislocated. I bet you wanted to put it after the do to get the value again.

The second mistake is your xargs usage. Since the list of files you want to pass to xargs might be empty, you'd add the switch --no-run-if-empty to fix the rm: missing operand error.

To avoid writing the check line twice you could write a while-true loop and check the condition inside and break out of the loop, since bash has no head-controlled while-loop.

while [ true ]; do
check = ...
if [ $check -le 10000 ]; then
break
fi

...
done

Other sugestions

  • You don't need to do the cd every time in the loop, do it before
  • If you'd like to remove files older than a specific amount of time rather than by checking the directory size you may use find -mtime +N (find files with modification date older (+) than N days)
  • Sometimes bash's pushd and popd are very convinient over cd because cd has changed the directory after script execution you'd need to remember the previous directory to cd back. Withpushdyou tell bash to do set the current directory wherepopd` brings you back to the previous directory. On directory stack functions


Related Topics



Leave a reply



Submit