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 split
s 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 (+
) thanN
days) - Sometimes bash's
pushd
andpopd
are very convinient overcd
becausecd
has changed the directory after script execution you'd need to remember the previous directory tocd back. With
pushdyou tell bash to do set the current directory where
popd` brings you back to the previous directory. On directory stack functions
Related Topics
Bash: /Bin/Tar: Argument List Too Long When Compressing Many Files with Tar
Search and Replace Text in All Files of a Linux Directory
Flex Development on Linux, What's a Good Free Environment
How to Conveniently Sync a File Between Two Git Repositories
Listing All User-Installed Packages in Debian
When a Parent Process Is Killed by "Kill -9", Will Subprocess Also Be Killed
How to Use Curl in a Shell Script
Docker Ignores Limits.Conf (Trying to Solve "Too Many Open Files" Error)
Openssh Client Hangs on Logout When Forwarding X Connections
How to Develop Linux Screen Saver
How to Configure Curl to Only Show Percentage
Lowering Linux Kernel Timer Frequency
What Is the Best Emacs Workspaces Plugin
Open Vim from Within a Bash Shell Script
Why Would It Be Impossible to Fully Statically Link an Application